воскресенье, 28 декабря 2008 г.

Поиск слов по шаблону в Lingvo

У многих кто изучает английский язык и активно пользуются  ПК стоит Lingvo. По крайней мере я и все мои знакомые пользуются именно этим словарем. Функции, которой мне нахватало был поиск слова по шаблону. Недавно, пролистывая брошюрку, которая идет с коробочной версией лингво обнаружил что такая функция есть и причем уже достаточно давно. Функция поиска по шаблону (в справке она называется поиск по маске) поддерживает известные символы подстановки “*” и “?” – любые буквы в любом количестве и одна любая буква соответственно.

Работает такой поиск следующим образом. В строку поиска надо ввести интересующий шаблон, например “he*o” и нажать Ctrl+F3. Программа запустит поиск по всем активным словарям и выведет окно с подходящими словами и словосочетаниями.

Search by Mask Result

четверг, 18 декабря 2008 г.

Интеллект Live Search

Давно знал, что поисковик Google может быть использован как простой калькулятор, но вот вчера с удивлением обнаружил, что майкрософтовский Live Search умеет решать уравнения. И что поразило меня еще больше, что нелинейные уравнение ему тоже по зубам. Вот парочка примеров (кликабельно):   

Единственный недостаток, что расширенным интеллектом обладает только англоязычная версия поисковика.

суббота, 23 августа 2008 г.

Sysinternals Desktops v1.0

«Широко известный в узких кругах» пакет утилит Sysinternals Suit пополнился еще одним приложением – Desktops v1.0. Эта утилита решает проблему переполненности панели задач и позволяет создавать до 4 виртуальных рабочих столов и работать раздельно с приложениями на каждом из них. Например, разрабатывать приложение в одном и просматривать почту и писать отчет в другом. Между приложениями на разных десктопах удобно переносить данные, так как они имеют один общий буфер обмена. Переключаться между десктопами можно по горячим клавишам или при помощи иконки в трэе.

В целом с приложением удобно работать, хотя есть определенные ограничения. Некоторые сочетания клавиш, например, Ctrl+Shif+ Esc (запуск Windows Task Manager) работают только в первом рабочем столе, (там, где была утилита запущена), не смотря на то, в каком рабочем столе такое сочетание клавиш было нажато, приложение запустится в первом.
Скачать утилиту можно здесь.

среда, 6 августа 2008 г.

Определение Integrity Level для процесса на c#

В Windows Vista появился дополнительный механизм защиты – Integrity Levels. В зависимости от его уровня различаются и возможности приложения по работе с защищенными ресурсами системы. Поэтому актуальной задачей является определение значения Integrity Level процесса. В MSDN есть пример по определению Integrity Level текущего процесса для неуправляемого кода (статья Appendix D: Getting the Integrity Level for an Access Token). Ниже я привел подобный код на C#. Я постарался сохранить стиль кода с оригиналом, что бы их было проще сравнивать. Так же, на мой взгляд, в оригинальном примере есть ошибка в определении уровней High и System. Поэтому я заменил фрагмент кода
else if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID) 
{
// High Integrity
...
}

на
else if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID && 
dwIntegrityLevel < SECURITY_MANDATORY_SYSTEM_RID)
{
// High Integrity
...
}

А вот и пример консольного приложения, которое определяет свой текущий Integrity Level.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Diagnostics;

namespace IntegrityLevel
{
class Program
{
static void Main(string[] args)
{
ShowProcessIntegrityLevel();
}

public static void ShowProcessIntegrityLevel()
{
IntPtr hProcess = Process.GetCurrentProcess().Handle;
IntPtr hToken;
if (!OpenProcessToken(hProcess,
TokenAccessLevels.MaximumAllowed,
out hToken))
{
return;
}

try
{
uint dwLengthNeeded;
if (GetTokenInformation(hToken,
TOKEN_INFORMATION_CLASS.TokenIntegrityLevel,
IntPtr.Zero,
0,
out dwLengthNeeded))

uint dwError = (uint)Marshal.GetLastWin32Error();
if (dwError == ERROR_INSUFFICIENT_BUFFER)
{
IntPtr pTIL = Marshal.AllocHGlobal((int)dwLengthNeeded);
try
{
if (!GetTokenInformation(hToken,
TOKEN_INFORMATION_CLASS.TokenIntegrityLevel,
pTIL,
dwLengthNeeded,
out dwLengthNeeded))
{
return;
}

TOKEN_MANDATORY_LABEL TIL =
(TOKEN_MANDATORY_LABEL)Marshal.PtrToStructure(pTIL,
typeof(TOKEN_MANDATORY_LABEL));

IntPtr SubAuthorityCount = GetSidSubAuthorityCount(TIL.Label.Sid);

IntPtr IntegrityLevelPtr = GetSidSubAuthority(TIL.Label.Sid,
Marshal.ReadByte(SubAuthorityCount) - 1);

int dwIntegrityLevel = Marshal.ReadInt32(IntegrityLevelPtr);

if (dwIntegrityLevel == SECURITY_MANDATORY_LOW_RID)
{
// Low Integrity
Console.WriteLine("Low Process");
}
else if (dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID &&
dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID)
{
// Medium Integrity
Console.WriteLine("Medium Process");
}
else if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID &&
dwIntegrityLevel < SECURITY_MANDATORY_SYSTEM_RID)
{
// High Integrity
Console.WriteLine("High Integrity Process");
}
else if (dwIntegrityLevel >= SECURITY_MANDATORY_SYSTEM_RID)
{
// System Integrity
Console.WriteLine("System Integrity Process");
}
}
finally
{
Marshal.FreeHGlobal(pTIL);
}
}
}
finally
{
CloseHandle(hToken);
}
}

// interop
const uint ERROR_INSUFFICIENT_BUFFER = 122;
const long SECURITY_MANDATORY_LOW_RID = 0x00001000L;
const long SECURITY_MANDATORY_MEDIUM_RID = 0x00002000L;
const long SECURITY_MANDATORY_HIGH_RID = 0x00003000L;
const long SECURITY_MANDATORY_SYSTEM_RID = 0x00004000L;

enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups = 2,
TokenPrivileges = 3,
TokenOwner = 4,
TokenPrimaryGroup = 5,
TokenDefaultDacl = 6,
TokenSource = 7,
TokenType = 8,
TokenImpersonationLevel = 9,
TokenStatistics = 10,
TokenRestrictedSids = 11,
TokenSessionId = 12,
TokenGroupsAndPrivileges = 13,
TokenSessionReference = 14,
TokenSandBoxInert = 15,
TokenAuditPolicy = 16,
TokenOrigin = 17,
TokenElevationType = 18,
TokenLinkedToken = 19,
TokenElevation = 20,
TokenHasRestrictions = 21,
TokenAccessInformation = 22,
TokenVirtualizationAllowed = 23,
TokenVirtualizationEnabled = 24,
TokenIntegrityLevel = 25,
TokenUIAccess = 26,
TokenMandatoryPolicy = 27,
TokenLogonSid = 28,
MaxTokenInfoClass = 29
}

[StructLayout(LayoutKind.Sequential)]
struct TOKEN_MANDATORY_LABEL
{
public SID_AND_ATTRIBUTES Label;
}

[StructLayout(LayoutKind.Sequential)]
struct SID_AND_ATTRIBUTES
{
public IntPtr Sid;
public int Attributes;
}

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool OpenProcessToken(IntPtr ProcessHandle,
TokenAccessLevels DesiredAccess,
out IntPtr TokenHandle);

[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(IntPtr TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation,
uint TokenInformationLength,
out uint ReturnLength);

[DllImport("kernel32.dll")]
static extern IntPtr LocalAlloc(uint uFlags, UIntPtr uBytes);

[DllImport("advapi32.dll", SetLastError = true)]
static extern IntPtr GetSidSubAuthority(IntPtr pSid, int nSubAuthority);

[DllImport("advapi32.dll", SetLastError = true)]
static extern IntPtr GetSidSubAuthorityCount(IntPtr pSid);
}
}

пятница, 18 июля 2008 г.

Взаимодействие процессов по IPCChanel

Недавно столкнулся с необходимостью организовать взаимодействие двух .NET процессов в рамках одного компьютера. Немного покумекав, решил для этих целей воспользоваться «родной» для платформы .NET технологией – Remoting. Первоначально в качестве канала для «общения» процессов планировал выбрать протокол TCP (TcpChannel), но затем обнаружил что во втором фреймворке появился новый канал ремоутинга, который идеально подходит для мой задачи – IpcChannel. Этот канал использует в своей работе именованные каналы (named pipes) и был разработан специально для организации взаимодействия нескольких процессов в рамках одного компьютера и согласно MSDN, работает намного быстрее TCP и HTTP. Использование технологии Remoting крайне просто и ниже я привел пример сервера и клиента взаимодействующих по каналу IpcChannel.
Ниже приведен код для сервера.
class ServerHost
{
static void Main( string[] args )
{
IDictionary settings = new Hashtable();
settings["portName"] = "IPC_Test";
settings["exclusiveAddressUse"] = false;

IChannel channel = new IpcChannel(settings, null, null);
ChannelServices.RegisterChannel(channel, false);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof( GreetingService ),
"GreetingService",
WellKnownObjectMode.Singleton );

Console.WriteLine("Server started. Press ENTER to shutdown.");
Console.ReadLine();
ChannelServices.UnregisterChannel( channel );
}
}

Далее идет код для клиента этого сервера
class ClientApp
{
static void Main( string[] args )
{
IGreetingService service = (IGreetingService)Activator.GetObject(
typeof( IGreetingService ),
"ipc://IPC_Test/GreetingService" );

Console.WriteLine(service.GetGreeting("IPC Tester"));
Console.ReadLine();
}
}

И наконец, пример интерфейса и реализация сервиса, который используемых как клиентом, так и сервером.
public interface IGreetingService
{
string GetGreeting(string userName);
}

class GreetingService: MarshalByRefObject, IGreetingService
{
public string GetGreeting( string userName )
{
return "Hello, " + userName;
}
}
Обратите внимание на установку параметра exclusiveAddressUse в false. В MSDN есть предупреждение, что установка его в false позволит нескольким серверам использовать одни и тот же порт, что может привести к брешам в безопасности такой архитектуры, однако если его не установить в false используемый сервером порт может быть недоступным еще около 1 секунды после завершения работы сервера.
Ниже приведен еще один пример реализации хоста сервера, но настройка ремоутинга произведена посредством конфигурационного файла.
class ConfigServerHost
{
static void Main( string[] args )
{
RemotingConfiguration.Configure( "ConfigServerHost.exe.config", false );

Console.WriteLine( "Server started. Press ENTER to shutdown" );
Console.ReadLine();
}
}

И наконец, app.config, который после компиляции проекта преврацается в ConfigServerHost.exe.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application name="IPC Sample">
<service>
<wellknown mode="Singleton" type="ServerHost.GreetingService, ServerHost" objectUri="GreetingService" />
</service>

<channels>
<channel ref="ipc" portName="IPC_Test" exclusiveAddressUse="false" />
</channels>
</application>
</system.runtime.remoting>
</configuration>

суббота, 12 июля 2008 г.

«Незаметный» запуск внешних процессов

Иногда возникает необходимость запустить внешний процесс, получить от него какие-либо данные (либо просто дать ему возможность отработать) и затем его закрыть. В .NET Framework для этих целей служит класс System.Diagnostics.Process и с этим классом запуск процессов весьма прост. Однако внешний процесс становится виден пользователю (часто это можно наблюдать при работе инсталляторов), что, вообще-то говоря, нежелательно. А вот чтобы запустить внешний процесс незаметно для пользователя, надо в классе настроек запуска процесса ProcessStartInfo свойству WindowStyle присвоить значение ProcessWindowStyle.Hidden. Но, как гласит русская народная пословица, лучше один раз увидеть, чем сто раз услышать, и поэтому ниже представлен небольшой пример «незаметного» запуска процессов. Приведенный фрагмент кода запускает утилиту Reg.exe (Console Registry Tool for Windows) и делает бэкап ветки реестра HKEY_CLASSES_ROOT\mailto в файл.

static void Main()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = "reg";
startInfo.Arguments = @"save HKEY_CLASSES_ROOT\mailto c:\mailto.reg";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);

}

понедельник, 7 июля 2008 г.

P/Invoke Interop Assistant

Команда CLR Interop недавно выпустила новый инструмент под названием P/Invoke Interop Assistant. Как можно догадаться из названия, он умеет генерировать код на С# и VB.NET для вызова native функций в .net приложениях. На рисунке ниже представлено главное окно P/Invoke Interop Assistant.

Если сравнивать его с другим популярным инструментом подобного рода – PInvoke.net, то в целом они очень похожи, хотя и есть некоторые отличия. На рисунке ниже изображено главное окно PInvoke.net.

P/Invoke Interop Assistant реализован отдельным инструментом и более функционален: в нем реализован контекстный поиск, есть генерация для типов и что особенно удобно есть генерация кода констант. Однако большая функциональность делает его несколько более сложным в использовании.
PInvoke.net существенно проще в использовании, и интегрируется в студию (в главном меню появляется пункт PInvoke.net). Ко всему прочему, PInvoke.net генерирует более простой код.