Archive for the Visual C++ Category

Sử dụng DLL trong .NET

Posted in Visual C++, Visual Studio 2005, Windows API on Tháng Tư 20, 2007 by Phạm Quang Hoà

Trong các chương trình viết trên nền .NET, ngoài việc sử dụng bộ thư viện được cung cấp bởi .NET Framework, đôi khi chúng ta có nhu cầu sử dụng các hàm được viết trên nền Windows, như các hàm API của Windows. Thông thường, các hàm này được cài đặt trong các thư viện liên kết động (DLL), được dịch bằng một trình dịch nào đó như MS Visual C++ hay Borland Delphi.

Các thư viện khi phát hành thường gồm 3 tệp, tệp tiêu đề có phần mở rộng .h chứa khai báo các hàm, tệp thư viện nhập có phần mở rộng .lib và tệp thư viện liên kết động có phần mở rộng .dll.

Để sử dụng các hàm của thư viện liên kết động trong .NET, chỉ cần tệp .dll là đủ, ngoài ra còn cần tệp .h để biết nguyên mẫu các hàm, từ đó khai báo các hàm trong .NET một cách đúng đắn.

Trong bài này, tôi giới thiệu cách sử dụng các hàm viết trong một thư viện liên kết động, được dịch bằng Visual C++ trong một chương trình viết trên nền .NET. Thư viện minh hoạ trong bài học này là thư viện đã được giới thiệu trong bài Thư viện liên kết động, môn học Lập trình Windows. Đây là một thư viện đơn giản với hai hàm: hàm tính luỹ thừa và hàm tính giai thừa.

Tệp tiêu đề của thư viện được khai báo như sau:
/* MyDll.h */
#ifndef __MYDLL_H__
#define __MYDLL_H__

#ifdef MYDLL_EXPORTS
#define MYDLLEXPORT _declspec(dllexport)
#else
#define MYDLLEXPORT _declspec(dllimport)
#endif

MYDLLEXPORT LONG CALLBACK Factorial(UINT);
MYDLLEXPORT DOUBLE CALLBACK Power(DOUBLE, UINT);

#endif // __MYDLL_H__

Tệp nguồn của thư viện:

/* MyDll.c */
#include
#include “MyDll.h”

LONG CALLBACK Factorial(UINT n)
{
  return (n > 0)?n*Factorial(n – 1):1;
}

DOUBLE CALLBACK Power(DOUBLE x, UINT n)
{
  return (n > 0)?x*Power(x, n – 1): 1;
}

Để sử dụng thư viện này trong .NET, dùng khai báo hàm với từ khoá extern và thuộc tính DllImport. Chương trình sau sẽ khai báo và sử dụng hai hàm này.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace UsingDll {
  class Program {
    [DllImport("MyDll.dll")]
    private static extern int Factorial(int n);

    [DllImport("MyDll.dll")]
    private static extern double Power(double x, int n);

    static void Main(string[] args) {
      Console.WriteLine(“2.0 to power 3 is {0}”,
        Power(2.0, 3));
      Console.WriteLine(“Factorial of 5 is {0}”,
        Factorial(5));
    }
  }
}

Một trong những vấn đề thường gặp phải khi sử dụng hàm viết trên nền Windows trong .NET là kiểu dữ liệu giữa hai nền không giống nhau. Sau đây là một vài kiểu chuyển đổi để có thể gọi hàm một cách đúng đắn.

Kiểu số nguyên 1 byte:
Windows: TCHAR (char), BYTE (unsigned char).
.NET: sbyte, byte (C#), Byte (VB.NET).

Kiểu số nguyên 4 byte:
Windows: int, UINT (unsigned int), DWORD (unsigned int), LONG (long).
.NET: int (C#), Integer (VB.NET) hoặc Int32.

Kiểu số thực 4 byte:
Windows: float.
.NET: float (C#), Single (VB.NET)

Kiểu số thực 8 byte:
Windows: double.
.NET: double (C#), Double (VB.NET).

Kiểu xâu ký tự (vào):
Windows: LPCTSTR, LPSTR.
.NET: string (C#), String (VB.NET).

Kiểu xâu ký tự (ra):
Windows: LPSTR.
.NET: byte[], sbyte[] (C#), Byte [] (VB.NET)

Download:

Ghi chú:
- Các hàm trong DLL phải được dịch theo chế độ gọi stdcall. Để dịch theo chế độ stdcall, các hàm nên khai báo với chỉ thị _stdcall (WINAPI, CALLBACK) và đặt các tệp nguồn có phần mở rộng là .c. Để kiểm tra một hàm trong một DLL có sẵn có phải được gọi theo kiểu stdcall không, mở DLL và xem định dạng của hàm trong DLL phải có dạng _<Tên hàm>@<Độ dài tham số>. Ví dụ hai hàm trên sẽ có tên đầy đủ là: _Factorial@4 và _Power@12.

- Trong trường hợp lấy xâu ký tự ra từ hàm, cần phải truyền vào một mảng kiểu byte (ANSI) hoặc char (Unicode) đủ lớn, sau đó ghép các ký tự nhận được trong mảng để tạo thành xâu ký tự kiểu string.

Tài liệu xử lý ảnh

Posted in Visual C++, Windows API on Tháng Mười Một 27, 2006 by Phạm Quang Hoà

Có một số bạn muốn tìm hiểu thêm về các thao tác xử lý ảnh. Nói chung,
các thuật toán xử lý ảnh đều được giới thiệu đầy đủ trong các cuốn
sách, giáo trình Xử lý ảnh. Ngoài ra, các bạn có thể tìm kiếm trên
Internet với từ khoá “Image Processing”, “filter”.

Để có thể thao tác được với ảnh, nhất thiết phải biết cách truy cập
từng thành phần màu của từng điểm trong ảnh. Nếu sử dụng FreeImage, có
thể lấy khối bit dữ liệu ảnh bằng hàm FreeImage_GetBits.

Thông thường, các thao tác với ảnh là các thao tác với từng điểm ảnh
(Point Operations) hoặc với một khối điểm ảnh (Block Operations). Các
thao tác với điểm ảnh như: Brighness, Gamma, Invert, HSL… và các thao
tác với khối ảnh như: Smooth, Blur, Sharpen, Emboss, Distoring…

Sau đây là một số đường link tìm được, các bạn có thể tham khảo thêm.

Pack file format

Posted in Visual C++, Windows API on Tháng Mười Một 27, 2006 by Phạm Quang Hoà

File có phần mở rộng pak, thường được sử dụng để chứa tài nguyên trong
một số game, tiêu biểu là các game dùng engine Quake III, như HL, MoH
hay CoD.
Định dạng pak là định dạng file chứa không nén. Nó cho phép tạo một file chứa các file và thư mục tương tự như file zip hay rar.
File pak là một file nhị phân có cấu trúc khá đơn giản. File gồm 3 vùng chính:

  • pak header – chứa các thông tin về file pak.
  • file header table – một bảng các cấu trúc chứa thông tin về các file và thư mục.
  • file data – nội dung của các file được chứa.

Vùng pak header nằm ở đầu file có dạng:

typedef struct {
    unsigned long id;
    unsigned long tableofs;
    unsigned long tablelen;
} pakheader_t;

Trong đó id là dấu hiệu kiểm tra định dạng, có giá trị là PACK
(0×4B434150), tableofs là offset của vùng file header table và tablelen
là độ lớn vùng file header table (tính theo byte).

Vùng file header table là một bảng các cấu trúc chứa thông tin về file
và thư mục, mỗi cấu trúc đặc trưng cho một file hoặc thư mục trong file
pak. Địa chỉ vùng này được chỉ ra trong trường tableofs của pak header,
thường thì vùng này nằm ở cuối file. Cấu trúc file header có dạng:

typedef struct {
    char name[60];
    unsigned long size;
} fileheader_t;

Trong đó name là đường dẫn của file trong file pak, tính từ thư mục
gốc. Nếu đường dẫn này kết thúc bằng dấu ‘/’ (0×2F) hoặc ‘\’ (0×5C) thì
đó là thư mục rỗng, còn không thì đó là file. Đường dẫn này có độ dài
tối đa là 59 ký tự, và không hỗ trợ Unicode. Trường size là kích cỡ của
file, tính theo byte. Trong trường hợp là thư mục rỗng thì trường size
không xác định (bằng 0).
Có thể tính số lượng các file header trong file header table bằng: tablelen/sizeof(fileheader_t)

Vùng file data chứa dữ liệu các file. Vùng này nằm ngay sau vùng pak
header, chứa nội dung các file bên trong, liên tiếp nhau theo thứ tự
chỉ ra trong vùng file header table.

Sơ đồ các vùng của file pak được mô tả trong hình dưới đây:

Image

Để dễ dàng hiểu được cách làm việc với file pak, các bạn có thể tham
khảo mã nguồn chương trình unpak. Ngoài ra, để tạo và thao tác với file
pak, các bạn có thể sử dụng chương trình PakScape.
File pak có thể sử dụng để đóng gói tài nguyên của các trò chơi, tránh
bị mất file dữ liệu nhưng vẫn đảm bảo truy cập dễ dàng. Ngoài ra, việc
hiểu rõ cấu trúc file pak còn cho phép lấy được nhiều tài nguyên của
các trò chơi hiện có.

Download: