1. 程式人生 > >用C#呼叫Windows API和其它程序通訊及C# 獲得另外一程式 控制代碼 後控制該程式 控制其透明 窗體大小

用C#呼叫Windows API和其它程序通訊及C# 獲得另外一程式 控制代碼 後控制該程式 控制其透明 窗體大小

作者:邊城浪子◎2005-01-16

關鍵字:
 C#
APIFindWindowFindWindowExSendMessage,程序,登錄檔

設計初衷:公司為了便於網路管理,使用了IEEE 802.1X的網路訪問控制,這樣每次開機需要輸入兩次登入密碼,於是我就研究了一下用C#來幫我輸入第二此登入的密碼

設計思想:主要是通過呼叫Windows API中的一些方法,主要使用的也就是FindWindowFindWindowExSendMessage這三個函式,迴圈遍歷當前的所有視窗,找 到目標視窗和程序以後把儲存在特定位置的使用者名稱密碼以及域資訊自動填入輸入框中,然後再觸發一下button事件,最後程式本身退出。

環境:在Windows 2000中文版 + sp4VS.net 2003中文版下開發在Windows 2000中文版下測試通過

程式截圖:

具體設計這個Form的程式碼就略過不詳細說了

為了使用Win32 API,需要先引入下面這個名稱空間:

using System.Runtime.InteropServices;

另外還需要用到程序和登錄檔,所以還需要引入下面的兩個名稱空間:

using System.Threading;
using Microsoft.Win32;

下面的程式碼是用來新增對API的引用:

Dll Import#region Dll Import

    [DllImport("User32.dll",EntryPoint="FindWindow")]
    

privatestaticextern IntPtr FindWindow(string lpClassName,
string lpWindowName);

    [DllImport("user32.dll",EntryPoint="FindWindowEx")]
    
privatestaticextern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter, 
string lpszClass, string lpszWindow);

    [DllImport("User32.dll",EntryPoint="SendMessage")]
    
privatestaticexternint SendMessage(IntPtr hWnd,
int Msg, IntPtr wParam, string lParam);

    
#endregion

主要用到的就是這三個方法,具體的我這裡就不詳細介紹了,請參考MSDN

需要用到的一些引數:

constint WM_GETTEXT = 0x000D;
    
constint WM_SETTEXT = 0x000C;
    
constint WM_CLICK = 0x00F5;

從名稱上應該就可以瞭解這些引數具體的含義是什麼了,而且這些引數都可以通過VS附帶的工具Spy ++查到。

下面是整個程式的核心部分,查詢窗體並對它進行操作:

SearchWindow#region SearchWindow
    
privateint SearchWindow()
    
{
        
int retval = 0; //
增加一個返回值用來判斷操作是否成功

        //
下面的這些引數都可以用Spy++查到
string lpszParentClass = "#32770"; //整個視窗的類名string lpszParentWindow = "本地連線"; //視窗標題string lpszClass = "Edit"; //需要查詢的子視窗的類名,也就是輸入框string lpszClass_Submit = "Button"; //需要查詢的Button的類名string lpszName_Submit = "確定"; //需要查詢的Button的標題string text = "";

        IntPtr ParenthWnd = 
new IntPtr(0);
        IntPtr EdithWnd = 
new IntPtr(0);

        
//查到窗體,得到整個窗體        ParenthWnd = FindWindow(lpszParentClass,lpszParentWindow);

        
//判斷這個窗體是否有效if (!ParenthWnd.Equals(IntPtr.Zero))
        
{
            
//得到User Name這個子窗體,並設定其內容            EdithWnd = FindWindowEx(ParenthWnd,EdithWnd,lpszClass,"");
            
if (!EdithWnd.Equals(IntPtr.Zero))
            
{
                text = 
this.tbUserName.Text.Trim();
                
//呼叫SendMessage方法設定其內容                SendMessage(EdithWnd, WM_SETTEXT, (IntPtr)0, text);
                retval ++;
            }

            
//得到Password這個子窗體,並設定其內容            EdithWnd = FindWindowEx(ParenthWnd,EdithWnd,lpszClass,"");
            
if (!EdithWnd.Equals(IntPtr.Zero))
            
{
                text = 
this.tbPassword.Text.Trim();
                SendMessage(EdithWnd, WM_SETTEXT, (IntPtr)0, text);
                retval ++;
            }

            
//得到Domain這個子窗體,並設定其內容            EdithWnd = FindWindowEx(ParenthWnd,EdithWnd,lpszClass,"");
            
if (!EdithWnd.Equals(IntPtr.Zero))
            
{
                text = 
this.tbDomain.Text.Trim();
                SendMessage(EdithWnd, WM_SETTEXT, (IntPtr)0, text);
                retval ++;
            }

            
//得到Button這個子窗體,並觸發它的Click事件            EdithWnd = FindWindowEx(ParenthWnd,
                EdithWnd,lpszClass_Submit,lpszName_Submit);
            
if (!EdithWnd.Equals(IntPtr.Zero))
            
{
                SendMessage(EdithWnd,WM_CLICK,(IntPtr)0,"0");
                retval ++;
            }
        }

        
return retval;
    }
    
#endregion

這裡有一點需要說明的是,當一個窗體下面有幾個類名相同的子窗體時,也就是說如果有三個輸入框,這三個輸入框的類名都是Edit,查詢結果是依次從 上往下的,最開始我不知道該怎麼辦才能分出具體的每個不同的輸入框,後來只能這樣一個一個來查詢來試一下,沒想到居然是對的。(有別的辦法麼?)

上面的這段程式碼也只適用於中文版的作業系統,因為不同的作業系統下同一個窗體的名稱都是不一樣的,我這裡也沒有英文版的系統,所以也沒辦法進行測試。

為了免去每次都讓使用者手動輸入的煩惱,我需要把這些資訊都儲存到一個特定的檔案裡面去,當用戶在第一次執行這個程式的時候,只需要輸入一次,點下 Save,先把這些資訊儲存到一個檔案中,然後再把程式本身載入到系統啟動項裡去,這樣下次開機的時候程式就可以自啟動,然後從檔案中讀取資訊完成以下的操作。

選擇存放檔案的路徑:

privatestring UserPro = 
        System.Environment.GetEnvironmentVariable("USERPROFILE");
    
privatestring PATH = System.Environment.GetEnvironmentVariable("USERPROFILE") + @"/Local Settings/AutoLog.ini";

當用戶點下Save按鈕所觸發的事件:

Button Submit Click#region Button Submit Click
    
privatevoid btSubmit_Click(object sender, System.EventArgs e)
    
{
        SaveData();
    }

    
privatevoid SaveData()
    
{
        
try{
            
//Save Data
            FileInfo obj = new FileInfo(PATH);
            
if(obj.Exists)
                obj.Delete();

            FileStream ofile = 
new FileStream(PATH,FileMode.Create);
            
//Hidden the file
            File.SetAttributes(PATH,FileAttributes.Hidden);
            StreamWriter sw = 
new StreamWriter(ofile);
            
//
把使用者名稱密碼和域資訊寫入檔案            sw.WriteLine(this.tbUserName.Text);
            sw.WriteLine(
this.tbPassword.Text);
            sw.WriteLine(
this.tbDomain.Text);
            sw.Flush();

            sw.Close();
            ofile.Close();

            
//把當前檔案拷貝到指定位置,然後再新增到登錄檔的啟動項裡string opath = Application.StartupPath + @"/Login.exe";
            
string tpath = UserPro + @"/Local Settings/Login.exe";
            
if(File.Exists(tpath))
                File.Delete(tpath);
            File.Copy(opath,tpath);

            RegistryKey hklm = Registry.CurrentUser;
            RegistryKey run = 
hklm.CreateSubKey(@"SOFTWARE/Microsoft/Windows/CurrentVersion/Run");
            run.SetValue("AutoLogin",tpath);

            
//最後程式退出            MessageBox.Show("OK","Information",
MessageBoxButtons.OK,MessageBoxIcon.Information);
            Application.Exit();
        }
        
catch(Exception ex)
        
{
            MessageBox.Show(ex.ToString(),"Error",
MessageBoxButtons.OK,MessageBoxIcon.Error);
        }
    }
    
#endregion

這樣的話,程式就可以從檔案中讀取已經存放好的資訊來進行驗證了。最後要做的就是,需要單獨開一個程序來迴圈執行上面的SearchWindow這個方法,直到找到符合條件的視窗併成功驗證為止,並且這個程序需要隨程式的啟動而啟動。

我們可以在建構函式中新增一個名為LoadData的方法,然後在這個方法中進行具體的讀檔案資訊和啟動程序的操作。

當然,先定義好這個程序:

private Thread thread;

然後是LoadData這個方法:

Load#region Load

    
privatevoid LoadData()
    
{
        
//Load Data
        FileStream ofile = new FileStream(PATH,FileMode.OpenOrCreate);
        StreamReader sr = 
new StreamReader(ofile);
        
this.tbUserName.Text = sr.ReadLine();
        
this.tbPassword.Text = sr.ReadLine();
        
this.tbDomain.Text = sr.ReadLine();

        sr.Close();
        ofile.Close();

        
//Thread Start
        thread = new Thread(new ThreadStart(Watch));
        thread.IsBackground = 
true;
        thread.Start();
    }
        
    
privatevoid Watch()
    
{
        
//
迴圈查詢這個視窗,直到成功為止while(true)
        
{
            
int i = this.SearchWindow();

            
if(i == 4)
                
break;
        }

        
//程式退出並釋放資源        Application.Exit();
        
this.Dispose();
        
this.Close();
        }

        
#endregion

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication2
{
    public partial class Form4 : Form
    {
        public Form4()
        {
            InitializeComponent();
        }
        [DllImport("user32.dll")]
        private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
        [DllImport("user32.dll")]
        private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpszClass, string lpszWindow);
        [DllImport("user32.dll")]
        public static extern bool SetLayeredWindowAttributes(
            IntPtr hWnd, int crKey, byte bAlpha, int dwFlags);
        [DllImport("user32.dll")]
        public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate,
            IntPtr hrgnUpdate, uint flags);

        public const int GWL_EXSTYLE = -20;
        public const int WS_EX_LAYERED = 0x00080000;
        public const int LWA_ALPHA = 0x00000002; public const int RDW_INVALIDATE = 1; public const int RDW_ERASE = 4; public const int RDW_ALLCHILDREN = 0x80; public const int RDW_FRAME = 0x400;

        private void button1_Click(object sender, EventArgs e)
        {
            //設定透明
            IntPtr vHandle = FindWindow("Notepad", null);
            // 這裡換成你獲得的窗體控制代碼,測試的時候可以用記事本。
            SetWindowLong(vHandle, GWL_EXSTYLE, GetWindowLong(vHandle, GWL_EXSTYLE) | WS_EX_LAYERED);
            SetLayeredWindowAttributes(vHandle, 0, 255 / 2/*透明度*/, LWA_ALPHA);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //恢復
            IntPtr vHandle = FindWindow("Notepad", null); SetWindowLong(vHandle, GWL_EXSTYLE, GetWindowLong(vHandle, GWL_EXSTYLE) & ~WS_EX_LAYERED); RedrawWindow(vHandle, IntPtr.Zero, IntPtr.Zero, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
        }

        [DllImport("user32.dll")]
        public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

        private void button3_Click(object sender, EventArgs e)
        {
            //改變窗體大小和位置
            IntPtr vHandle = FindWindow("Notepad", null); MoveWindow(vHandle, 20, 20, 200, 200, true);
        }

    }
}

相關推薦

C#呼叫Windows API其它程序通訊C# 獲得另外程式 控制 控制程式 控制透明 窗體大小

作者:邊城浪子◎2005-01-16 關鍵字:  C#,API,FindWindow,FindWindowEx,SendMessage,程序,登錄檔 設計初衷:公司為了便於網路管理,使用了IEEE 802.1X的網路訪問控制,這樣每次開機需要輸入兩次登入密碼,於是我就研究了

Visual C#呼叫Windows API函式

用Visual C#呼叫Windows API函式         Api函式是構築Windws應用程式的基石,每一種Windows應用程式開發工具,它提供的底層函式都間接或直接地呼叫了Windows API函式,同時為了實現功能擴充套

C#呼叫Windows圖片傳真檢視器開啟圖片

//建立新的系統程序 System.Diagnostics.Process process = new System.Diagnostics.Process(); //設定檔名,此處為圖片的真實路徑+檔名 process.StartInfo.FileName =

C#呼叫Windows API(示例:顯示工作管理員裡的程式名稱)

作為初學者來說,在C#中使用API確是一件令人頭疼的問題。 在使用API之前你必須知道如何在C#中使用結構、型別轉換、安全/不安全程式碼,可控/不可控程式碼等許多知識。 在.Net Framework SDK文件中,關於呼叫Windows API的指示比較零散,並且其中稍全面一點的是針對Visual Basi

C# 在建立視窗控制之前,不能在控制元件上呼叫 Invoke 或 BeginInvoke

http://www.cnblogs.com/fish124423/archive/2012/10/16/2726543.html   在Invoke(....)之前加上1 this.components==null 2 this.IsDisposed 3 IsHandleCreated 來re

.NET物件與Windows控制(二):控制分類.NET控制洩露的例子

上一篇文章介紹了控制代碼的基本概念,也描述了C#中建立檔案控制代碼的過程。我們已經知道控制代碼代表Windows內部物件,檔案物件就是其中一種,但顯然系統中還有更多其它型別的物件。本文將簡單介紹Windows物件的分類。 控制代碼可以代表的Windows物件分為三類,核心物件(Kernel Object)、

"在建立視窗控制之前,不能在控制元件上呼叫 Invoke 或 BeginInvoke"

“在Window窗體程式開發的時候,如果使用多執行緒程式設計,在子執行緒中訪問主執行緒窗體內的控制元件,就需要使用控制元件的Control.Invoke方法或者BeginInvoke方法。但是有時候因為Window執行速度太快,尤其是你寫程式碼的時候在Ini

多執行緒委託之跨執行緒問題分析--在建立視窗控制之前,不能在控制元件上呼叫 Invoke 或 BeginInvoke(解決方法已更新)

檢視巢狀檢視+groupby+sum+if超慢?檢視巢狀檢視+groupby+sum+if超慢? 炯蕉蔚郝iar貉k湯秤TP2Fx扯訃詬壤撞蝸 《 http://babyknow.baidu.com/article/1376a5480527629546e457877078

ASP.NET Core 2.1 建立規範的 REST API -- 保護API其它

本文介紹如何保護API,無需看前邊文章也能明白吧。 預備知識:  建立成熟度2級的 API請看這裡: 認證和授權 認證/身份驗證 Authentication, 是驗證想要訪問特定資源的人/系統的身份的過程. 授權 Authorization, 是確認已認證的

Python3 requests呼叫Zabbix API

環境版本: Python 3.6 requests 2.21 Zabbix 3.4 #!/usr/bin/env python #_*_ coding:utf-8 _*_ import requests import json class Zabbix_api(): def __i

go呼叫windows api

 golang呼叫windows的api函式,方法:  import ( "fmt" "syscall" "unsafe" ) func abort(funcname string, err int) { panic(funcname + " failed: " +

C# 呼叫win32API 獲取程序控制 有毛用???

private void button2_Click(object sender, EventArgs e) { Process[] ProceddingCon = Process.GetProcesses(); //獲得所有程序 Int

判斷檔案、目錄是否存在:CC++、Windows API、 boost

一、判斷檔案是否存在 #ifdef WIN32 #include <io.h>                      //C (Windows)    access #else #include <unistd.h>           

JNI進階 (C++呼叫java屬性方法,javap的使用)

一、C/C++函式分析://獲取jclass物件,引數:this的意思,就是native方法所在的類1.GetObjectClass(jobject) //獲取普通屬性id,第一個引數:類物件, 第二個引數:屬性名,第三個引數:屬性簽名(不知道的同學點選這裡)2.GetFie

C#呼叫RESTful API

現在很多的網路服務都用RESTful API來實現。比如百度的搜尋推廣API介紹使用Rest原因:REST+JSON風格的API相比SOAP+XML,好處是:呼叫更加靈活,也更容易擴充套件;JSON格式傳輸資訊比XML減少約30%的資料量,效率更高。因此建議開發

Openwrt下C呼叫UCI API

“uci”是”Unified Configuration Interface”(統一配置介面)的縮寫,意在OpenWrt整個系統的配置集中化。 許多程式在系統某處擁有自己的配置檔案,比如/etc/network/interfaces, /etc/expor

c++呼叫靜態庫動態庫

呼叫靜態庫 第一步把動態庫放到檔案裡 第二部連線上靜態庫 #pragma comment(lib,"靜態庫.lib") 呼叫動態庫 第一步 typedef int( *getMaxNum)(i

windows核心程式設計-程序控制如何獲得

程序控制代碼不同於程序核心物件的控制代碼 程序核心物件控制代碼:代表整個程序的 程序控制代碼:exe或者dll裝入某個程序的地址空間,有唯一的例項控制代碼,也可以叫做模組控制代碼 程序控制代碼的本質是程序模組在程序地址空間中的首地址! 一:GetModuleFileName

C++使用Windows API CreateMutex函式多執行緒程式設計

C++中也可以使用Windows 系統中對應的API函式進行多執行緒程式設計。使用CreateThread函式建立執行緒,並且可以通過CreateMutex建立一個互斥量實現執行緒間資料的同步: #

如何呼叫WINDOWS 圖片傳真檢視器”

在WINDOWS XP中,“WINDOWS 圖片和傳真檢視器”這個應該程式並沒有一個真正存在的EXE檔案,他是從一個DLL中呼叫而來的,具體呼叫方法如下: 我們需要用rundll32.exe這個程式來執行含有這個功能的DLL(shimgvw.dll),並附加引數ImageVi