В качестве продолжения серии 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).