311 Chương 8: Đồ họa, đa phương tiện, và in ấn using System; using System.Runtime.InteropServices; using Microsoft.VisualBasic; public class BeepTest { [DllImport("kernel32.dll")] private static extern bool Beep(int freq, int dur); [STAThread] private static void Main(string[] args) { // Phát tiếng "beep" tần số 440 Hz trong 100 mili-giây // trên internal speaker. Console.WriteLine("Win32 API beep test."); Beep(440, 100); Console.ReadLine(); // Phát tiếng "beep" mặc định của hệ thống (file WAV). Console.WriteLine("VB beep test."); Interaction.Beep(); Console.ReadLine(); } } Bạn cũng có thể sử dụng các hàm Win32 API để chơi một file âm thanh do bạn chọn. Kỹ thuật này được mô tả trong mục 8.10. 10. 10. Ch i file audioơ Ch i file audioơ Bạn cần chơi một file WAV hoặc MP3 . Sử dụng hàm API sndPlaySound (hỗ trợ file WAV ), hoặc sử dụng thành phần ActiveMovie có trong Windows Media Player (hỗ trợ file WAV và MP3 ) Để chơi bất kỳ âm thanh nào trong một ứng dụng .NET, bạn cần nhận sự giúp đỡ của một thư viện bên ngoài hoặc lời gọi hệ thống. May mắn thay, cả hai tùy chọn này đều dễ dàng thực hiện được. 312 Chương 8: Đồ họa, đa phương tiện, và in ấn • Thư viện winmm.dll (có trong Windows) chứa hàm sndPlaySound nhận vào tên của một file WAV và một thông số chỉ định cách chơi. Bạn có thể chọn chơi âm thanh một cách đồng bộ (gián đoạn việc thực thi của chương trình cho đến khi âm thanh đã hoàn tất), bất đồng bộ, hoặc trong một vòng lặp chạy phía nền. • Thư viện Quartz cung cấp một thành phần COM có thể chơi nhiều kiểu file audio, gồm các định dạng WAV và MP3. Thư viện Quartz được cấp thông qua quartz.dll và nó là một phần của Microsoft DirectX cho Windows Media Player và hệ điều hành Windows. Trong ví dụ này, chúng ta sẽ sử dụng cách tiếp cận thứ hai. Bước đầu tiên là tạo một lớp Interop có thể quản lý sự tương tác giữa ứng dụng .NET và thư viện Quartz. Bạn có thể tạo một lớp C# cùng với đoạn mã Interop này bằng tiện ích Type Library Importer (tlbimp.exe) và dòng lệnh sau đây ( [WindowsDir] là đường dẫn của thư mục cài đặt Windows): tlbimp [WindowsDir]\system32\quartz.dll /out:QuartzTypeLib.dll Bạn có thể sử dụng Visual Studio .NET để tạo lớp Interop bằng cách thêm vào một tham chiếu. Chỉ cần nhắp phải vào dự án của bạn trong Solution Explorer, và chọn Add Reference từ menu ngữ cảnh. Kế tiếp, chọn thẻ COM, và cuộn xuống để chọn ActiveMovie control type library (xem hình 8.7). Một khi lớp Interop đã được tạo, bạn có thể làm việc với giao diện IMediaControl . Bạn có thể chỉ định file mà bạn muốn chơi bằng RenderFile , và có thể điều khiển playback bằng các phương thức như Run , Stop , và Pause . Playback diễn ra trên một tiểu trình độc lập, như thế nó sẽ không block đoạn mã của bạn. 313 Chương 8: Đồ họa, đa phương tiện, và in ấn Hình 8.7 Chọn ActiveMovie control type library trong hộp thoại Add Reference Ví dụ, tiện ích Console dưới đây sẽ chơi file audio được chỉ định trong đối số dòng lệnh đầu tiên: using System; class PlayAudio { public static void Main(string[] args) { // Lấy tên file được chỉ định trong đối số đầu tiên. string filename = args[0]; // Truy xuất giao diện IMediaControl. QuartzTypeLib.FilgraphManager graphManager = new QuartzTypeLib.FilgraphManager(); QuartzTypeLib.IMediaControl mc = (QuartzTypeLib.IMediaControl)graphManager; // Chỉ định tên file. mc.RenderFile(filename); // Bắt đầu chơi file audio bất đồng bộ. mc.Run(); Console.WriteLine("Press Enter to continue."); Console.ReadLine(); mc.Stop(); } } Bạn cũng có thể sử dụng thư viện Quartz để hiển thị file video (sẽ được trình bày trong mục 8.11). 11. 11. Ch i file videoơ Ch i file videoơ Bạn cần chơi một file video (như MPEG , AVI , hoặc WMV ) ngay trên form. Sử dụng thành phần ActiveMovie có trong Media Player . Gắn kết xuất video vào một PictureBox trên form bằng cách thiết lập thuộc tính IVideoWindow.Owner là thuộc tính PictureBox.Handle . 314 Chương 8: Đồ họa, đa phương tiện, và in ấn .NET Framework không chứa bất kỳ lớp được-quản-lý nào để tương tác với các file video, nhưng bạn có thể sử dụng chức năng DirectShow của thư viện Quartz dựa-trên-COM (có trong Windows Media Player và hệ điều hành Windows). Để biết cách tạo một Interop Assembly cho thư viện Quartz, bạn hãy tham khảo mục 8.10. Một khi đã tạo Interop Assembly, bạn có thể sử dụng giao diện IMediaControl để nạp và chơi một file video. Về cơ bản, kỹ thuật này giống như kỹ thuật đã trình bày trong mục 8.10 với file audio. Tuy nhiên, nếu muốn hiển thị cửa sổ video ngay bên trong giao diện ứng dụng của bạn (hơn là trong một cửa sổ độc lập), bạn phải sử dụng giao diện IVideoWindow . Đối tượng FilgraphManager có thể được ép kiểu thành giao diện IMediaControl và IVideoWindow —và nhiều giao diện khác cũng được hỗ trợ như IBasicAudio (cho phép bạn cấu hình các thiết lập balance và volume). Với giao diện IVideoWindow , bạn có thể gắn kết xuất video vào một đối tượng trên form như Panel hoặc PictureBox . Để làm được như vậy, bạn cần thiết lập thuộc tính IVideoWindow.Owner là handle của điều kiểm đó (bạn có thể lấy được handle này bằng thuộc tính Control.Handle ). Kế tiếp, gọi IVideoWindow.SetWindowPosition để thiết lập kích thước và vị trí của cửa sổ. Phương thức này cũng có thể được gọi để thay đổi kích thước video trong quá trình playback (chẳng hạn, khi form bị thay đổi kích thước). Ví dụ dưới đây cho phép người dùng mở bất kỳ file video nào và chơi nó trong một PictureBox . PictureBox bị neo đến tất cả các cạnh của form, như thế nó cũng thay đổi kích thước khi form bị thay đổi kích thước. Đoạn mã đáp ứng cho sự kiện PictureBox.SizeChanged sẽ thay đổi kích thước của cửa sổ video tương ứng. using System; using QuartzTypeLib; using System.Windows.Forms; public class ShowMovie : System.Windows.Forms.Form { private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.Button cmdOpen; // (Bỏ qua phần mã designer.) // Định nghĩa các hằng dùng để chỉ định window style. private const int WM_APP = 0x8000; private const int WM_GRAPHNOTIFY = WM_APP + 1; private const int EC_COMPLETE = 0x01; private const int WS_CHILD = 0x40000000; private const int WS_CLIPCHILDREN = 0x2000000; 315 Chương 8: Đồ họa, đa phương tiện, và in ấn // Giữ tham chiếu mức-form đến giao diện Media Control, // để đoạn mã có thể điều khiển playback cho // movie được nạp hiện tại. private IMediaControl mc = null; // Giữ tham chiếu mức-form đến cửa sổ video trong // trường hợp nó cần được thay đổi kích thước. private IVideoWindow videoWindow = null; private void cmdOpen_Click(object sender, System.EventArgs e) { // Cho phép người dùng chọn file. OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "Media Files|*.mpg;*.avi;*.wma;*.mov;" + "*.wav;*.mp2;*.mp3|All Files|*.*"; if (DialogResult.OK == openFileDialog.ShowDialog()) { // Dừng playback đối với movie hiện tại, nếu nó tồn tại. if (mc != null) mc.Stop(); // Nạp file movie. FilgraphManager graphManager = new FilgraphManager(); graphManager.RenderFile(openFileDialog.FileName); // Gắn cửa sổ video vào PictureBox trên form. try { videoWindow = (IVideoWindow)graphManager; videoWindow.Owner = (int) pictureBox1.Handle; videoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN; videoWindow.SetWindowPosition( pictureBox1.ClientRectangle.Left, pictureBox1.ClientRectangle.Top, pictureBox1.ClientRectangle.Width, pictureBox1.ClientRectangle.Height); 316 Chương 8: Đồ họa, đa phương tiện, và in ấn } catch { // Lỗi có thể xảy ra nếu file không có // video source (chẳng hạn, file MP3). // Bạn có thể bỏ qua lỗi này và vẫn cho phép // playback tiếp tục (không có hình). } // Bắt đầu playback (bất đồng bộ). mc = (IMediaControl)graphManager; mc.Run(); } } private void pictureBox1_SizeChanged(object sender, System.EventArgs e) { if (videoWindow != null) { try { videoWindow.SetWindowPosition( pictureBox1.ClientRectangle.Left, pictureBox1.ClientRectangle.Top, pictureBox1.ClientRectangle.Width, pictureBox1.ClientRectangle.Height); } catch { // Bỏ qua ngoại lệ (bị ném khi thay đổi kích thước form) // khi file không có video source. } } } 317 Chương 8: Đồ họa, đa phương tiện, và in ấn private void ShowMovie_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (mc != null) mc.Stop(); } } Hình 8.8 Chơi file video trong PictureBox trên form 12. 12. L y thông tin v các máy in đã đ c cài đ tấ ề ượ ặ L y thông tin v các máy in đã đ c cài đ tấ ề ượ ặ Bạn cần lấy danh sách các máy in đang có hiệu lực trên máy tính. Đọc tên các máy in đã được cài đặt trong tập hợp InstalledPrinters của lớp System.Drawing.Printing.PrinterSettings . Lớp PrinterSettings mô tả các thiết lập cho một máy in và thông tin về máy in đó. Ví dụ, bạn có thể sử dụng lớp PrinterSettings để xác định các khổ giấy (paper size), các nguồn giấy (paper source), và các độ phân giải (resolution) được hỗ trợ và kiểm tra khả năng in màu hoặc in hai mặt. Ngoài ra, bạn có thể lấy các thiết lập trang mặc định cho lề (margin), hướng trang (orientation) Lớp PrinterSettings cung cấp tập hợp tĩnh InstalledPrinters , tập hợp này chứa tên của tất cả các máy in đã được cài đặt trên máy tính. Nếu muốn tìm thêm thông tin về các thiết lập cho một máy in cụ thể, bạn cần tạo một đối tượng PrinterSettings và thiết lập thuộc tính PrinterName cho phù hợp. Ứng dụng Console dưới đây sẽ tìm tất cả các máy in đã được cài đặt trên máy tính và hiển thị thông tin về khổ giấy và độ phân giải được hỗ trợ bởi mỗi máy in. using System; using System.Drawing.Printing; 318 Chương 8: Đồ họa, đa phương tiện, và in ấn public class ListPrinters { private static void Main(string[] args) { foreach (string printerName in PrinterSettings.InstalledPrinters) { // Hiển thị tên máy in. Console.WriteLine("Printer: {0}", printerName); // Lấy các thiết lập máy in. PrinterSettings printer = new PrinterSettings(); printer.PrinterName = printerName; // Kiểm tra tính hợp lệ của máy in. // (Bước này cần thiết trong trường hợp bạn đọc tên máy in // từ một giá trị do người dùng cấp hoặc một thiết lập trong // file registry hay configuration.) if (printer.IsValid) { // Hiển thị danh sách các độ phân giải hợp lệ. Console.WriteLine("Supported Resolutions:"); foreach (PrinterResolution resolution in printer.PrinterResolutions) { Console.WriteLine(" {0}", resolution); } Console.WriteLine(); // Hiển thị danh sách các khổ giấy hợp lệ. Console.WriteLine("Supported Paper Sizes:"); foreach (PaperSize size in printer.PaperSizes) { if (Enum.IsDefined(size.Kind.GetType(), size.Kind)) { 319 Chương 8: Đồ họa, đa phương tiện, và in ấn Console.WriteLine(" {0}", size); } } Console.WriteLine(); } } Console.ReadLine(); } } Dưới đây là kết xuất mà ứng dụng này có thể hiển thị: Printer: SnagIt 7 Supported Resolutions: [PrinterResolution High] [PrinterResolution Medium] [PrinterResolution Low] [PrinterResolution Draft] [PrinterResolution X=600 Y=600] [PrinterResolution X=300 Y=300] [PrinterResolution X=200 Y=200] [PrinterResolution X=100 Y=100] Supported Paper Sizes: [PaperSize Letter Kind=Letter Height=1100 Width=850] [PaperSize Legal Kind=Legal Height=1400 Width=850] [PaperSize Executive Kind=Executive Height=1050 Width=725] [PaperSize A4 Kind=A4 Height=1169 Width=827] [PaperSize Envelope #10 Kind=Number10Envelope Height=950 Width=412] [PaperSize Envelope DL Kind=DLEnvelope Height=866 Width=433] [PaperSize Envelope C5 Kind=C5Envelope Height=902 Width=638] [PaperSize Envelope B5 Kind=B5Envelope Height=984 Width=693] [PaperSize Envelope Monarch Kind=MonarchEnvelope Height=750 Width=387] Printer: Adobe PDF Supported Resolutions: [PrinterResolution High] [PrinterResolution Medium] [PrinterResolution Low] 320 Chương 8: Đồ họa, đa phương tiện, và in ấn [PrinterResolution Draft] [PrinterResolution X=72 Y=72] [PrinterResolution X=144 Y=144] [PrinterResolution X=300 Y=300] [PrinterResolution X=600 Y=600] [PrinterResolution X=1200 Y=1200] [PrinterResolution X=2400 Y=2400] [PrinterResolution X=3600 Y=3600] [PrinterResolution X=4000 Y=4000] Supported Paper Sizes: [PaperSize Letter Kind=Letter Height=1100 Width=850] [PaperSize Tabloid Kind=Tabloid Height=1700 Width=1100] [PaperSize Ledger Kind=Ledger Height=1100 Width=1700] [PaperSize Legal Kind=Legal Height=1400 Width=850] [PaperSize Executive Kind=Executive Height=1050 Width=725] [PaperSize A3 Kind=A3 Height=1654 Width=1169] [PaperSize A4 Kind=A4 Height=1169 Width=827] [PaperSize A2 Kind=A2 Height=2339 Width=1654] [PaperSize 11 x 17 Kind=Custom Height=1700 Width=1100] [PaperSize Screen Kind=Custom Height=518 Width=650] [PaperSize ANSI C Kind=Custom Height=2200 Width=1700] [PaperSize ANSI D Kind=Custom Height=3400 Width=2200] [PaperSize ANSI E Kind=Custom Height=4400 Width=3400] [PaperSize ANSI F Kind=Custom Height=4000 Width=2800] Bạn không cần thực hiện cách làm này khi tạo một ứng dụng cung cấp chức năng in. Theo mục 8.13, bạn có thể sử dụng PrintDialog để nhắc người dùng chọn một máy in và các thiết lập cho nó. Lớp PrintDialog có thể tự động áp dụng các thiết lập của nó cho PrintDocument mà không cần viết thêm mã lệnh. Bạn có thể in một văn bản trong bất kỳ kiểu ứng dụng nào. Tuy nhiên, ứng dụng của bạn phải chứa một tham chiếu đến System.Drawing.dll . Nếu đang sử dụng một kiểu dự án trong Visual Studio .NET không có tham chiếu này (như ứng dụng Console ), bạn cần phải thêm nó vào. . mô tả các thiết lập cho một máy in và thông tin về máy in đó. Ví dụ, bạn có thể sử dụng lớp PrinterSettings để xác định các khổ giấy (paper size), các nguồn giấy (paper source), và các độ. y thông tin v các máy in đã đ c cài đ tấ ề ượ ặ L y thông tin v các máy in đã đ c cài đ tấ ề ượ ặ Bạn cần lấy danh sách các máy in đang có hiệu lực trên máy tính. Đọc tên các máy in đã. tên của tất cả các máy in đã được cài đặt trên máy tính. Nếu muốn tìm thêm thông tin về các thiết lập cho một máy in cụ thể, bạn cần tạo một đối tượng PrinterSettings và thiết lập thuộc tính