• Thứ Năm, 01/10/2009 14:41 (GMT+7)

    Lập trình tương tác bằng VB6

    Lượt xem 2254
    Đánh giá

    Câu hỏi :
    Xin hướng dẫn cách viết 1 chương trình bằng VB 6.0 có thể tương tác với 1 ứng dụng khác. Ví dụ, khi chạy chương trình sẽ tự động gọi file iTunes.exe, sau đó đăng nhập và nhận biết đăng nhập thành công hay thất bại từ thông báo của iTunes.
     

    Trả lời :
    Trong phần mềm viết bằng ngôn ngữ VB 6.0, để kích hoạt 1 chương trình khác chạy, bạn có thể gọi hàm API của Windows có tên là WinExec(). Thí dụ, muốn chạy ứng dụng "c:\program files\itunes\itunes.exe", bạn có thể viết lệnh sau:

     WinExec """c:\program files\itunes\itunes.exe""", 1
     Sau khi ứng dụng được kích hoạt chạy bởi lệnh WinExec(), nó sẽ chạy song hành và độc lập với phần mềm của bạn. Để tương tác tự động với ứng dụng khác, bạn phải biết trình tự thao tác cụ thể mà người dùng thực hiện nhằm yêu cầu 1 chức năng nào đó của ứng dụng rồi dùng lệnh SendKeys để tạo tự động trình tự thao tác đó.
     Thí dụ sau đây là qui trình xây dựng ứng dụng VB 6.0 nhỏ demo việc kích hoạt ứng dụng iTunes rồi yêu cầu nó dừng chạy khi cần thiết.
     1. Chạy VB 6.0, tạo Project dạng "Standard EXE"
     2. Khi Form ứng dụng rỗng hiển thị, bạn hãy vẽ 2 button có tên mặc định lần lượt là Command1 và Command2. Hiệu chỉnh caption cho Command1 là "Chạy iTunes" và caption cho Command2 là "Dừng iTunes".
     3. Nhấn đúp chuột vào button Command1 để hiển thị cửa sổ soạn code cho Form rồi viết đoạn lệnh VB sau:
     Option Explicit
     'khai báo các hằng cần dùng
     Const GW_CHILD = 5
     Const GW_HWNDNEXT = 2
     'khai báo các hàm API cần dùng
     Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
     Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
     Private Declare Function GetTopWindow Lib "user32" (ByVal hwnd As Long) As Long
     Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long
     Private Declare Function SetFocusWnd Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long
     Private Declare Function WinExec Lib "kernel32" (ByVal lpCmdLine As String, ByVal nCmdShow As Long) As Long
     Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
     
     'thủ tục xử lý click chuột vào button Command1
     Private Sub Command1_Click()
     'kích hoạt iTunes chạy
     WinExec """c:\program files\itunes\itunes.exe""", 1
     End Sub
     
     'thủ tục xử lý click chuột vào button Command2
     Private Sub Command2_Click()
     Dim hwnd As Long
     Do
     'tìm handle của cửa sổ iTunes
     hwnd = FindWindow("iTunes")
     Loop Until hwnd <> 0
     'cho cửa sổ iTunes hiển thị trên cùng và làm việc với user
     SetForegroundWindow hwnd
     SetFocusWnd hwnd
     'ngủ chờ 2 giây
     Sleep (2000)
     'tạo phím Alt-F để hiển thị menu File của iTunes
     SendKeys "%f"
     'ngủ chờ 2 giây
     Sleep (2000)
     'tạo phím x để yêu cầu iTunes dừng
     SendKeys "x"
     End Sub
     
     'hàm tìm handle của 1 cửa sổ ứng dụng có titlebar xác định
     Private Function FindWindow(stitlebar As String) As Long
     Dim WT As String, Length As Long
     Dim hwnd As Long
     FindWindow = 0
     hwnd = GetTopWindow(0)
     Do
     WT = Space(256)
     Length = GetWindowText(hwnd, WT, 255)
     WT = Left$(WT, Length)
     If WT = stitlebar Then
     FindWindow = hwnd
     Exit Function
     End If
     hwnd = GetWindow(hwnd, GW_HWNDNEXT)
     Loop Until hwnd = 0
     End Function
     4. Chọn menu Run.Start để chạy thử ứng dụng, nhấn vào button "Chạy iTunes" để kích hoạt iTunes chạy. Sau khi iTunes đã chạy, nhấn vào button "Dừng iTunes" để yêu cầu iTunes dừng chạy.
     
     
     Tôi muốn lập trình giả lập Windows Media Player cho Pocket PC, nhưng trong .Net compact Framework không hỗ trợ điều khiển Media như trong .Net framework. Vậy phải làm sao?
     Hiện nay, Microsoft đã phân phối điều khiển "Windows Media Player 10 Mobile (MP 10 Mobile)" cho máy Pocket PC và SmartPhone, do đó bạn có thể lập trình mobile dùng điều khiển này để chơi các file multimedia.
     
     Tôi có 1 ứng dụng nhỏ viết bằng C# truy xuất database, không hiểu sao thêm mới thì được nhưng xoá không được, và nếu đưa chỉ mục (dòng hiện hành) đến cuối thì phát sinh lỗi.
     Ứng dụng mà bạn viết thực hiện duyệt xem/cập nhật/thêm/xóa từng record trong bảng BangChude của file database (thí dụ có tên là d:\Mydatabase.mdb), mỗi record trong bảng có 2 field: field ID (làm key) và field Chude có nội dung là chuỗi. Sau khi đọc và kiểm tra chi tiết code trong Form chủ đề của bạn được liệt kê ở trên, chúng tôi thấy có khá nhiều lỗi: lỗi về hằng chuỗi, lỗi về chỉ số record cần truy xuất trong các đoạn code... Trong đó lỗi về việc xóa record như bạn thắc mắc là do nội dung trong đối tượng DataTable và DataAdapter không nhất quán với nhau. Chúng tôi đã sửa tất cả các lỗi của bạn để chương trình có thể chạy tốt. Để cho bạn và độc giả dễ theo dõi, chúng tôi giới thiệu qui trình điển hình để xây dựng ứng dụng của bạn:
     1. Chạy Visual Studio .Net, chọn menu File.New project. Khi cửa sổ "New Project hiển thị, bạn duyệt tìm mục "Visual C#" trong cửa sổ "Project types", chọn mục "Windows" con của "Visual C#", chọn icon "Windows Application" rồi chọn button Ok để tạo Project mới theo qui định.
     2. Khi cửa sổ hiển thị Form thiết kế trống ban đầu, bạn hãy chọn Form rồi đặt tên cho nó là frmThaoTacChuDe.
     3. Vẽ các đối tượng cần dùng cho form như sau:
     Hãy đặt tên cho 2 textbox lần lượt là tbChude và tbDhh, tên cho các button chức năng lần lượt là btLui, btTien, btCapnhat, btThemmoi, btGhi, btXoa.
     3. Nhấn đúp vào từng button để tạo hàm xử lý sự kiện click chuột vào button đó. Sau khi tạo được 6 hàm xử lý click chuột cho 6 button, bạn viết code cho từng hàm theo chức năng của nó. Cuối cùng, file source code cho Form frmThaoTacChuDe như sau:
     
     using System;
     using System.Collections.Generic;
     using System.ComponentModel;
     using System.Data;
     using System.Drawing;
     using System.Text;
     using System.Windows.Forms;
     
     //lệnh sau rất cần để dùng các đối tượng OleDb
     using System.Data.OleDb;
     namespace WindowsApplication1 {
     public partial class frmThaoTacChuDe : Form {
     //khai báo các thuộc tính cần dùng
     private OleDbDataAdapter bdg_CHU_DE;
     private DataTable bdl_CHU_DE;
     private OleDbConnection myConnection;
     private int dhh;
     //hàm khởi tạo form
     public frmThaoTacChuDe() {
     InitializeComponent();
     bdl_CHU_DE = new DataTable();
     btGhi.Enabled = false;
     dhh = 0;
     //tạo đối tượng Connection đến database
     myConnection = new OleDbConnection();
     myConnection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\\MyDatabase.mdb;";
     //tạo đối tượng DataAdapter
     bdg_CHU_DE = new OleDbDataAdapter("select * from BangChude", myConnection);
     //thiết lập lệnh Delete cho DataAdapter;
     bdg_CHU_DE.DeleteCommand = new System.Data.OleDb.OleDbCommand();
     bdg_CHU_DE.DeleteCommand.Connection = myConnection;
     bdg_CHU_DE.DeleteCommand = new System.Data.OleDb.OleDbCommand();
     bdg_CHU_DE.DeleteCommand.Connection = myConnection;
     bdg_CHU_DE.DeleteCommand.CommandText = "DELETE FROM `BangChude` WHERE ((`ID` = ?) AND ((? = 1 AND `Chude` IS NULL) OR (`Chude` = ?)))";
     bdg_CHU_DE.DeleteCommand.CommandType = System.Data.CommandType.Text;
     bdg_CHU_DE.DeleteCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_ID", System.Data.OleDb.OleDbType.Integer, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "ID", System.Data.DataRowVersion.Original, false, null));
     bdg_CHU_DE.DeleteCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("IsNull_Chude", System.Data.OleDb.OleDbType.Integer, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "Chude", System.Data.DataRowVersion.Original, true, null));
     bdg_CHU_DE.DeleteCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_Chude", System.Data.OleDb.OleDbType.VarWChar, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "Chude", System.Data.DataRowVersion.Original, false, null));
     //thiết lập lệnh Insert cho DataAdapter;
     bdg_CHU_DE.InsertCommand = new System.Data.OleDb.OleDbCommand();
     bdg_CHU_DE.InsertCommand.Connection = myConnection;
     bdg_CHU_DE.InsertCommand.CommandText = "INSERT INTO `BangChude` (`Chude`) VALUES (?)";
     bdg_CHU_DE.InsertCommand.CommandType = System.Data.CommandType.Text;
     bdg_CHU_DE.InsertCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Chude", System.Data.OleDb.OleDbType.VarWChar, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "Chude", System.Data.DataRowVersion.Current, false, null));
     //thiết lập lệnh Update cho DataAdapter;
     bdg_CHU_DE.UpdateCommand = new System.Data.OleDb.OleDbCommand();
     bdg_CHU_DE.UpdateCommand.Connection = myConnection;
     bdg_CHU_DE.UpdateCommand.CommandText = "UPDATE `BangChude` SET `Chude` = ? WHERE ((`ID` = ?) AND ((? = 1 AND `Chude` IS NULL) OR (`Chude` = ?)))";
     bdg_CHU_DE.UpdateCommand.CommandType = System.Data.CommandType.Text;
     bdg_CHU_DE.UpdateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Chude", System.Data.OleDb.OleDbType.VarWChar, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "Chude", System.Data.DataRowVersion.Current, false, null));
     bdg_CHU_DE.UpdateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_ID", System.Data.OleDb.OleDbType.Integer, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "ID", System.Data.DataRowVersion.Original, false, null));
     bdg_CHU_DE.UpdateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("IsNull_Chude", System.Data.OleDb.OleDbType.Integer, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "Chude", System.Data.DataRowVersion.Original, true, null));
     bdg_CHU_DE.UpdateCommand.Parameters.Add(new System.Data.OleDb.OleDbParameter("Original_Chude", System.Data.OleDb.OleDbType.VarWChar, 0, System.Data.ParameterDirection.Input, ((byte)(0)), ((byte)(0)), "Chude", System.Data.DataRowVersion.Original, false, null));
     bdg_CHU_DE.Fill(bdl_CHU_DE);
     hienthithongtin();
     }
     
     //hàm xử lý click button Lùi
     private void btLui_Click(object sender, EventArgs e) {
     dhh--;
     if (dhh == -1)
     dhh = bdl_CHU_DE.Rows.Count - 1;
     btCapnhat.Enabled = true;
     btXoa.Enabled = true;
     btGhi.Enabled = false;
     hienthithongtin();
     }
     
     //hàm xử lý click button Tiến
     private void btTien_Click(object sender, EventArgs e) {
     dhh++;
     if (dhh == bdl_CHU_DE.Rows.Count)
     dhh = 0;
     btCapnhat.Enabled = true;
     btXoa.Enabled = true;
     btGhi.Enabled = false;
     hienthithongtin();
     }
     
     //hàm xử lý click button Thêm mới
     private void btThemmoi_Click(object sender, EventArgs e){
     tbChude.Text = "";
     btCapnhat.Enabled = false;
     btXoa.Enabled = false;
     btGhi.Enabled = true;
     }
     
     //hàm xử lý click button Ghi
     private void btGhi_Click(object sender, EventArgs e) {
     DataRow dongdulieu;
     dongdulieu = bdl_CHU_DE.NewRow();
     bdl_CHU_DE.Rows.Add(dongdulieu);
     dhh = bdl_CHU_DE.Rows.Count - 1;
     if (tbChude.Text != "")
     bdl_CHU_DE.Rows[dhh]["Chude"] = tbChude.Text;
     try {
     btCapnhat.Enabled = true;
     btXoa.Enabled = true;
     btGhi.Enabled = false;
     bdg_CHU_DE.Update(bdl_CHU_DE);
     bdl_CHU_DE.Reset();
     bdg_CHU_DE.Fill(bdl_CHU_DE);
     hienthithongtin();
     MessageBox.Show("Ghi dữ liệu thành công!");
     }
     catch {
     MessageBox.Show("Ghi dữ liệu không thành công!");
     }
     }
     
     //hàm xử lý click button Xóa
     private void btXoa_Click(object sender, EventArgs e) {
     bdl_CHU_DE.Rows[dhh].Delete();
     try {
     bdg_CHU_DE.Update(bdl_CHU_DE);
     bdl_CHU_DE.Reset();
     bdg_CHU_DE.Fill(bdl_CHU_DE);
     dhh--;
     if (dhh == -1) dhh = 0;
     hienthithongtin();
     MessageBox.Show("Xóa dữ liệu thành công!");
     }
     catch {
     MessageBox.Show("Xóa dữ liệu không thành công!");
     }
     }
     
     //hàm hiển thị record cần xử lý hiện hành
     private void hienthithongtin() {
     tbChude.Text = bdl_CHU_DE.Rows[dhh]["Chude"].ToString();
     tbDhh.Text = dhh.ToString();
     }
     
     //hàm xử lý việc thay đổi chỉ số record cần xử lý
     private void tbDhh_TextChanged(object sender, EventArgs e) {
     btCapnhat.Enabled = true;
     btXoa.Enabled = true;
     btGhi.Enabled = false;
     try {
     int dong = int.Parse(tbDhh.Text.ToString());
     if ((dong < 0) || (dong > bdl_CHU_DE.Rows.Count - 1)) {
     MessageBox.Show("Không tồn tại dòng này!\nXin vui lòng nhập số từ 0 -" + (bdl_CHU_DE.Rows.Count - 1) + ".");
     tbDhh.Text = dhh.ToString();
     } else {
     dhh = dong;
     hienthithongtin();
     }
     } catch {
     MessageBox.Show("Kiểu dữ liệu không hợp lệ!");
     tbDhh.Text = dhh.ToString();
     }
     }
     
     //hàm xử lý click button Capnhat
     private void btCapnhat_Click(object sender, EventArgs e){
     if (tbChude.Text != "")
     bdl_CHU_DE.Rows[dhh]["Chude"] = tbChude.Text;
     try {
     bdg_CHU_DE.Update(bdl_CHU_DE);
     bdl_CHU_DE.Reset();
     bdg_CHU_DE.Fill(bdl_CHU_DE);
     MessageBox.Show("Cập nhật dữ liệu thành công!");
     } catch {
     MessageBox.Show("Cập nhật dữ liệu không thành công!");
     }
     }
     }
     }
     4. Chọn menu Debug.Start Debuging để chạy thử ứng dụng. Khi cửa sổ ứng dụng hiển thị, bạn thử chọn từng button chức năng và xem phản ứng của chương trình xem có đúng theo yêu cầu của mình không? Lưu ý file database mà chương trình trên truy xuất có đường dẫn là c:\MyDatabase.mdb, trong file đã có ít nhất 1 bảng tên là BangChude.
     
     Cách sử dụng phần mềm Lex và đoạn mã C mà có thể từ đó xây dựng một trình biên dịch?
     Module phân tích từ vựng là 1 trong nhiều module chức năng cấu thành 1 chương trình dịch ngôn ngữ. Cách dễ dàng và nhanh chóng nhất để xây dựng module phân tích từ vựng cho 1 ngôn ngữ nào đó là dùng ngôn ngữ Lex (Lexical Analyzer Generator). File Lex chứa các biểu thức chính quy, mỗi biểu thức chính quy miêu tả 1 token cụ thể của ngôn ngữ, định dạng tổng quát của file Lex như sau:
     %{
     //các lệnh định nghĩa viết bằng C hay C++
     %}
     %%
     //các biểu thức chính quy nhận dạng các token của ngôn ngữ
     %%
     //các đoạn code C hay C++ miêu tả ứng dụng
     Để bạn hiểu cụ thể và chi tiết, chúng tôi xin giới thiệu qui trình điển hình để viết 1 chương trình dịch rất đơn giản: duyệt file mã nguồn (text only), tìm mọi từ "toi" và dịch thành "I", mọi từ "anh" và dịch thành "You", các nội dung khác của mã nguồn vẫn giữ nguyên.
     1. Dùng bất kỳ trình soạn thảo văn bản nào để viết mã nguồn Lex giải quyết yêu cầu trên như sau (rồi lưu lên file mytrans.l):
     %{
     //các lệnh định nghĩa cần dùng
     #include <stdlib.h>
     %}
     
     %%
     [tT][oO][iI] { printf("I");}
     [aA][nN][hH] { printf("You");}
     . { printf("%c",yytext[0]); }
     %%
     
     //điểm nhập của ứng dụng
     void main(int argc, char *argv[]) {
     //mở file mã nguồn
     if ((yyin = fopen(argv[1],"r")) == 0) {
     printf("Không thể mở file %s!\n",argv[1]);
     return;
     }
     //gọi hàm yylex phân tích từ vựng
     yylex();
     fclose(yyin);
     return;
     }
     Lưu ý rằng toàn bộ đặc tả Lex sẽ được dịch ra thành hàm yylex() với nhiệm vụ thực hiện đúng những gì đặc tả. Trong thí dụ trên, chúng tôi chỉ đặc tả 2 token để nhận dạng 2 từ "toi" và "anh", mỗi lần gặp từ "toi" thì theo đặc tả, chương trình sẽ xuất ra từ "I", mỗi lần gặp từ "anh" chương trình sẽ xuất ra từ "You", còn khi gặp các ký tự khác thì chương trình xuất ra ký tự gốc chứ không biến đổi gì.
     2. Sau khi đã viết xong file Lex, bạn có thể dùng tool Lex dịch nó ra file *.c tương ứng. Vì tool Lex thường chạy ở chế độ dòng lệnh, bạn hãy tạo 1 cửa sổ "Command Prompt", dùng lệnh cd để chuyển thư mục làm việc về thư mục chứa file mã nguồn Lex rồi nhập lệnh sau để dịch file Lex ra file mytrans.c:
     flex -tl mytrans.l > mytrans.c
     
     3. Sau khi đã có file mytrans.c, bạn có thể dùng chương trình dịch C hay C++ dịch nó ra file khả thi. Thí dụ bạn có thể dùng trình dịch BorlandC++ để dịch file mytrans.c ra file khả thi như sau:
     bcc mytrans.c
     
     4. Sau khi đã có file khả thi, bạn có thể dùng nó. Thí dụ, bạn hãy dùng trình soạn thảo văn bản rồi soạn thử 1 file văn bản có chứa nhiều từ "toi" và "anh" (giả sử được lưu thành file mydoc.txt). Để dịch file nguồn ra file kết quả theo yêu cầu ở trên, bạn nhập lệnh sau:
     mytrans mydoc.txt > ketqua.txt 
     
    Ý kiến phản hồi và bình luận      Gởi ý kiến của bạn ?
    Chuyên mục: Lập trình