Разработка DLL на языке С++, страница 7

Заметим, что он прекрасно работает и без маршалинга параметров (без атрибута перед string s). Но маршалинг уточняет, что тип LPTSTR (Unicode-совместимая версия char*), действующий в этом конкретном случае по умолчанию, должен быть приведен к типу LPSTR (обычный тип char*). Функцию puts, импортированную из msvcrt.dll, оказывается, можно переименовать (присвоить ей любое другое имя, например, Out). Это делается так:

[DllImport("msvcrt.dll", EntryPoint="puts")]

public static extern int Out (string c);

static void Main() { Out ("Remnants of COM, ah? \n\n"); }

Покажем, как программным способом (используя функции API) переместить курсор в желаемую позицию.

[DllImport("User32.dll")]

public static extern bool SetCursorPos (int x, int y);

[DllImport("User32.dll")]

public unsafe static extern bool ClientToScreen (IntPtr hWnd, POINT* lp);

Вторая функция требует подать на вход аргумент типа HWND. Запомните, что в окружении NET ему соответствует тип IntPtr. Кроме того, вторая функция требует аргумент типа POINT*, то есть адрес структуры POINT, используемой в Win32 для работы с координатами точек в пределах окна. Для импорта структуры мы можем создать ее аналог, адекватно описанный в среде .NET, например:

[StructLayout(LayoutKind.Sequential)]

public struct POINT

{

public int x, y;    // Типу LONG в Win32-окружении соответствует тип int в среде NET

};

Для того, чтобы работать с указателем на эту структуру, следует использовать спецификатор unsafe и спокойно работать с адресами, как и в проекте типа Visual C++ Win32. Свойство Handle класса Form возвращает необходимый нам описатель окна типа HWND.

public unsafe void Test() //========= API-style

{

POINT p;

p.x = p.y = 10;

ClientToScreen (Handle, &p);

SetCursorPos (p.x, p.y);

}

Следующий вариант показывает, как обойтись без структуры POINT и использовать вместо нее существующую в NET структуру Point.

public unsafe void Test() //========= Mixed-style

{

Point pt = new Point (10, 40);

ClientToScreen (Handle, (POINT*)&pt);  // Необходимо привести тип

SetCursorPos (pt.X, pt.Y);

}

Так как внутри функции Testмы начинаем работать с указателями (а это опасно), то она должны быть отмечены описателем unsafe (опасная). Этого мало, весь проект нужно отметить, как опасный.

¨  Откройте Property Pages, найдите узел дерева с именем Configuration Properties4Build,

¨  Установите в True свойство Allow Unsafe Code Blocks и нажмите OK.

Наконец, покажем, как решить задачу без помощи Win32-API и обойтись только средствами NET.

public void Test() //========= Net-style. Описатель unsafe не нужен

{

Point pt = PointToScreen (new Point (10, 40));

Cursor.Position = (pt);

}

Следующий пример показывает, как импортировать API-функции CreateFontIndirect и DeleteObject и превратить их в статические методы класса Program. Кроме того, здесь показано, как импортировать Win32-структуру.

class Program

{

[StructLayout(LayoutKind.Sequential)]

public class LOGFONT

{

public const int LF_FACESIZE = 32;

public int lfHeight;

public int lfWidth;

public int lfEscapement;

public int lfOrientation;

public int lfWeight;

public byte lfItalic;

public byte lfUnderline;

public byte lfStrikeOut;

public byte lfCharSet;

public byte lfOutPrecision;

public byte lfClipPrecision;

public byte lfQuality;

public byte lfPitchAndFamily;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst=LF_FACESIZE)]

public string lfFaceName;

}

[DllImport("gdi32.dll", CharSet=CharSet.Auto)]

public static extern IntPtr CreateFontIndirect([In, MarshalAs(UnmanagedType.LPStruct)] LOGFONT lplf);

[DllImport("gdi32.dll")]

public static extern bool DeleteObject(IntPtr handle);

public static void Main()

{

LOGFONT lf = new LOGFONT();

lf.lfHeight = 9;

lf.lfFaceName = "Arial";

IntPtr handle = CreateFontIndirect(lf);

if (IntPtr.Zero == handle)

Console.WriteLine("Can't creates a logical font.");

else

{

if (IntPtr.Size == 4)