В качестве продолжения серии Windows Phone Native я решил добавить несколько очень простых методов в нативную оболочку, с которой я работаю. Он действует как расширение стандартного SDK и может вызывать возможности, которые (пока) не предоставляются через управляемые API.
ПРИМЕЧАНИЕ: я предполагаю, что вы уже следите за моей серией, и у вас есть основы для расширения проекта. Если нет, зайдите сюда и прочитайте вводную статью.
выход
Допустим, вы хотите выйти из приложения. Существует стандартный метод Exit, который можно реализовать, добавив ссылку на Microsoft.Xna.Framework . Общепринятой практикой является не использовать его в приложениях Silverlight, когда есть более приемлемые методы, такие как очистка backstack. Тем не менее, в исследовательских целях я должен отметить, что существует также способ естественного выхода из приложения и даже связывания с ним кода выхода . Взгляните на этот метод:
STDMETHODIMP CNativeAPI::ExitApplication() { exit(0); return S_OK; }
Просто вызвав метод выхода, я могу завершить свое собственное приложение. Все, что необходимо сделать, это добавить соответствующие объявления в IDL и заголовочные файлы.
MessageBeep
Двигаясь дальше, вы теперь хотите воспроизвести системный звуковой сигнал. Существует функция MessageBeep, что в стандартной ОС Windows имеет несколько возможных вариантов, как MB_ICONINFORMATION , MB_ICONWARNING или MB_OK . В этом случае существует только один стандартный звук (их должно быть больше, учитывая, что эти данные параметризованы в Guide.BeginShowMessageBox), который можно передать через значение uint. Так что метод довольно прост:
STDMETHODIMP CNativeAPI::PlaySystemSound(UINT sound) { BOOL result = MessageBeep(sound); if (result) return S_OK; else return 0x80070000 | ::GetLastError(); }
Вы можете спросить — почему я прошу пользователя добавить значение uint, когда доступен только один звук? Сам метод MessageBeep не работает без параметра. Поэтому жесткое кодирование значения не имеет большого смысла, поскольку настройки ОС могут в конечном итоге измениться.
GetSystemInfo
Эта функция вызывается для получения информации о процессоре, на котором работает ОС. Он опирается на структуру SYSTEM_INFO, которая содержит связанные значения DWORD и WORD . Вот быстрый и грязный подход для чтения системных данных:
STDMETHODIMP CNativeAPI::GetSystemInformation(SYSTEM_DATA* retData) { SYSTEM_DATA sysData; SYSTEM_INFO data; GetSystemInfo(&data); sysData.AllocationGranularity = data.dwAllocationGranularity; sysData.NumberOfProcessors = data.dwNumberOfProcessors; sysData.PageSize = data.dwPageSize; sysData.OEMID = data.dwOemId; sysData.ProcessorType = data.dwProcessorType; sysData.ActiveProcessorMask = data.dwActiveProcessorMask; sysData.ProcessorLevel = data.wProcessorLevel; sysData.ProcessorRevision = data.wProcessorRevision; sysData.ProcessorArchitecture = data.wProcessorArchitecture; *retData = sysData; return S_OK; }
Вы можете видеть, что существует также так называемая структура SYSTEM_DATA. Это пользовательская реализация, которую я представил для удобства чтения и переносимости. Он объявлен в файле IDL, связанном с основной библиотекой. Именно так:
typedef struct _SYSTEM_DATA { DWORD PageSize; DWORD ActiveProcessorMask; DWORD NumberOfProcessors; DWORD ProcessorType; DWORD AllocationGranularity; WORD ProcessorLevel; WORD ProcessorRevision; DWORD OEMID; WORD ProcessorArchitecture; } SYSTEM_DATA;
Как только я вызываю GetSystemInfo , я просто «транспортирую» данные в новую структуру. Та же самая структура будет использоваться в управляемом коде. Учитывая, что методы правильно объявлены на собственной стороне и DLL компилируется правильно, управляемый фрагмент теперь будет состоять из трех частей.
Объявление класса:
[ComImport, ClassInterface(ClassInterfaceType.None), Guid("8848DEB3-66B6-4AE3-A6F6-4A9C2F6595A5")] public class CNativeAPI { }
Объявление интерфейса:
[ComImport, Guid("57C3A135-837D-486F-93E3-BF878F61892B"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface INativeAPI { [return: MarshalAs(UnmanagedType.BStr)] string GetDeviceDriverInformation(); void PlaySystemSound(uint sound); void ExitApplication(); // Mainly CPU information. //************************** // ProcessorType //************************** // 2577 - STRONGARM //************************** // ProcessorLevel //************************** // 5 - ARMV5 (http://msdn.microsoft.com/en-us/library/ee488780.aspx) // Apparently the same applies to the OEM identificator. //************************** SYSTEM_DATA GetSystemInformation(); }
Объявление структуры для GetSystemInformation :
[StructLayout(LayoutKind.Sequential)] public struct SYSTEM_DATA { public uint PageSize; public uint ActiveProcessorMask; public uint NumberOfProcessors; public uint ProcessorType; public uint AllocationGranularity; public ushort ProcessorLevel; public ushort ProcessorRevision; public uint OEMID; public ushort ProcessorArchitecture; }
Вы можете просто вызвать информационный вызов с помощью фрагмента кода, подобного следующему:
SYSTEM_DATA data = NativeAPIHook.GetSystemInformation(); MessageBox.Show(data.ProcessorArchitecture.ToString());
Поскольку значения, которые вы будете получать, являются целыми числами, вам необходимо найти их значение в официальной документации MSDN для Windows CE и Mobile, учитывая, что они являются константами и не требуют пояснений (например, NumberOfProcessors вернет 1).