<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>graywolf's lair &#187; Code snippets</title>
	<atom:link href="http://graywolf.org.ua/category/articles/it/snippets/feed/" rel="self" type="application/rss+xml" />
	<link>http://graywolf.org.ua</link>
	<description>Inhuman being's diary</description>
	<pubDate>Mon, 01 Dec 2008 21:37:04 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6</generator>
	<language>en</language>
			<item>
		<title>Найпростіша plugin-архітектура на python</title>
		<link>http://graywolf.org.ua/2007/12/20/%d0%bd%d0%b0%d0%b9%d0%bf%d1%80%d0%be%d1%81%d1%82%d1%96%d1%88%d0%b0-plugin-%d0%b0%d1%80%d1%85%d1%96%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d0%b0-%d0%bd%d0%b0-python/</link>
		<comments>http://graywolf.org.ua/2007/12/20/%d0%bd%d0%b0%d0%b9%d0%bf%d1%80%d0%be%d1%81%d1%82%d1%96%d1%88%d0%b0-plugin-%d0%b0%d1%80%d1%85%d1%96%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d0%b0-%d0%bd%d0%b0-python/#comments</comments>
		<pubDate>Thu, 20 Dec 2007 19:24:22 +0000</pubDate>
		<dc:creator>graywolf</dc:creator>
		
		<category><![CDATA[Code snippets]]></category>

		<category><![CDATA[itblog-ua]]></category>

		<guid isPermaLink="false">http://graywolf.org.ua/2007/12/20/%d0%bd%d0%b0%d0%b9%d0%bf%d1%80%d0%be%d1%81%d1%82%d1%96%d1%88%d0%b0-plugin-%d0%b0%d1%80%d1%85%d1%96%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d0%b0-%d0%bd%d0%b0-python/</guid>
		<description><![CDATA[Так вже вийшло, що мені вдруге довелося писати модульну систему на пітоні. Причому вдруге довелося йти по одних і тих самих граблях, бо приклад минулої реалізації залишився на ноуті, який зараз лежить в сервісному центрі. Шлях нижче не являється оптимальним чи там найкращим, але головне, що він 100% робочий і задовольняє моїм потребам  А [...]]]></description>
			<content:encoded><![CDATA[<p>Так вже вийшло, що мені вдруге довелося писати модульну систему на пітоні. Причому вдруге довелося йти по одних і тих самих граблях, бо приклад минулої реалізації залишився на ноуті, який зараз лежить в сервісному центрі. Шлях нижче не являється оптимальним чи там найкращим, але головне, що він 100% робочий і задовольняє моїм потребам <img src='http://graywolf.org.ua/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> А потреби полягають в тому, що кожен плагін представляє собою реалізацію класу з певним набором функцій та має засіб для інстанціювання об&#8217;єкту цього класу не знаючи його імені. Отож&#8230; <span id="more-181"></span></p>
<p>Для початку створимо приблизно наступну систему підкаталогів з файлами, а потім почнемо її наповнювати:</p>
<pre lang="shell">+ / plugins
| |
| + / plugin1
| | |
| | - __init__.py
| |
| + / plugin2
| | |
| | - __init__.py
| |
| - __init__.py
|
- pluginmanager.py</pre>
<p>Як неважко здогадатись, модуль <em>plugingmanager.py</em> - буде відповідати за завантаження плагінів. Папка <em>plugins</em> міститиме власне плагіни (кожен з яких буде займати окремий каталог) та файл ініціалізації пакету &#8220;plugins&#8221; (файл <em>__init__.py</em>) - його можна лишити порожнім, оскільки надпакет <em>plugins</em> використовується лише для групування.</p>
<textarea name="code" class="python" cols="80" rows="10">#!/usr/bin/python
import os
 
plugins = []
 
def LoadModule(module):
    # build package name
    packagename = "plugins." + module
    # using built-in function __import__() to dynamically load modules; ensure that
    # directory containing "plugins" folder exists in python's sys.path list 
    # if not, it can be specified by sys.path.append(path_to_plugins) command before calling __import__()
    mod = __import__(packagename, globals(), locals(), [])

    # if module import was successful
    if ( mod ):
        # try to get the plugin module itself
        components = packagename.split('.')
        for component in components[1:]:
            mod = getattr(mod, component)
        # add the instance of plugin-implemented class to the list
        plugins.append(mod.CreateInstance())
 
# dynamicaly load plugin packages
def LoadPlugins(pluginpath):
    # enum plugins directory
    for dir in os.listdir(pluginpath + "\\plugins"):
        # for each non-hidden file or directory
        if dir[0] != "_":
            # try to load corresponding plugin
            LoadModule(dir)

LoadPlugins(".")
for plugin in plugins:
	plugin.Say("Joey")</textarea>
<p>Сподіваюсь, коментарі зрозумілі (хоч і англомовні <img src='http://graywolf.org.ua/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ). Отож, ми перебираємо папку з плагінами і для кожого файлу (тобто в нашому випадку каталогу) намагаємось імпортувати його по імені. В пітоні завдяки вищенаведеній структурі будується дерево пакетів. Тобто в нашому випадку у нас є пакет верхнього рівня <em>plugins</em>, який має два підпакети: <em>plugins.plugin1</em> та <em>plugins.plugin2</em>. Для імпорту використовується вбудована функція __import__(). Вона повертає клас модуля верхнього рівня (в нашому випадку - &#8220;plugins&#8221;), але оскільки нам потрібно дійти до пакета нижнього рівня ми &#8220;занурюємось&#8221; далі використовуючи рекурсивно функцію attrib. В нашому випадку, звісно, можна було зробити простіше, оскільки вкладеність тут має лише один рівень і назва пакету будується в цій же функції, але код я трохи ускладнив спеціально, щоб дати більш загальну та гнучку реалізацію завантаження пакетів чи модулів.</p>
<p>Отримавши клас модуля ми викликаємо його глобальну функцію <em>CreateInstance()</em>, що поверне нам екземпляр реалізованого в модулі класу.</p>
<p>Тепер розглянемо реалізацію власне плагінів. Для нескладних випадків ми можемо запихнути її прямо в опис пакету plugin1 - файл <em>__init__.py</em>:</p>
<textarea name="code" class="python" cols="80" rows="10">#!/usr/bin/python

class Plugin1():
	def Say(self, name):
		print "Hello, %s!" % name

def CreateInstance():
	return Plugin1()</textarea>
<p>По аналогії можна зробити і реалізацію plugin2. Тепер запустивши програму отримаємо наступне:</p>
<textarea name="code" class="python" cols="80" rows="10">$ ./pluginmanager.py
Hello, Joey!
Konnichiwa, Joey!</textarea>
<p>Набір відповідних плагінів можна тепер збільшувати просто додаючи по аналогії інші підкаталоги-пакети. Звісно, можна переробити це все з підтримкою модулів, а не пакетів (чи не лише пакетів), але мені все ж така структура подобається більше.
<div class="meta">
</div>
]]></content:encoded>
			<wfw:commentRss>http://graywolf.org.ua/2007/12/20/%d0%bd%d0%b0%d0%b9%d0%bf%d1%80%d0%be%d1%81%d1%82%d1%96%d1%88%d0%b0-plugin-%d0%b0%d1%80%d1%85%d1%96%d1%82%d0%b5%d0%ba%d1%82%d1%83%d1%80%d0%b0-%d0%bd%d0%b0-python/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Заміна URL для Live search в IE</title>
		<link>http://graywolf.org.ua/2007/08/30/%d0%b7%d0%b0%d0%bc%d1%96%d0%bd%d0%b0-url-%d0%b4%d0%bb%d1%8f-live-search-%d0%b2-ie/</link>
		<comments>http://graywolf.org.ua/2007/08/30/%d0%b7%d0%b0%d0%bc%d1%96%d0%bd%d0%b0-url-%d0%b4%d0%bb%d1%8f-live-search-%d0%b2-ie/#comments</comments>
		<pubDate>Thu, 30 Aug 2007 14:45:37 +0000</pubDate>
		<dc:creator>graywolf</dc:creator>
		
		<category><![CDATA[Code snippets]]></category>

		<guid isPermaLink="false">http://graywolf.org.ua/?p=54</guid>
		<description><![CDATA[Одразу маленька відмазка: те, що надалі описане мені потрібно було виключно по роботі. Сам я IE не користуюсь - лише Оперою та Файрфоксом  
Не дивлячись на те, що сабжева задача здається вельми і вельми тривіальною насправді все не атк просто. Мається на увазі URL, по якому переходить браузер, якщо ви введети якусь маячню в [...]]]></description>
			<content:encoded><![CDATA[<p>Одразу маленька відмазка: те, що надалі описане мені потрібно було виключно по роботі. Сам я IE не користуюсь - лише Оперою та Файрфоксом <img src='http://graywolf.org.ua/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Не дивлячись на те, що сабжева задача здається вельми і вельми тривіальною насправді все не атк просто. Мається на увазі URL, по якому переходить браузер, якщо ви введети якусь маячню в <em>Location Bar</em> (напр. набір слів, або неіснуючий домен). Точніше велику проблему це становить для IE6. Для Internet Explorer 7 все вирішується просто - URL для закачки міняється правкою ключа реєстру:</p>
<p><em>HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\SearchScopes\{0633EE93-D776-472f-A0FF-E1416B8B2E3A}\URL</em></p>
<p>Міняємо прописаний там майкрософтівський Live search на щось типу:</p>
<p><em>http://www.google.com.ua/search?hl=uk&#038;q=<strong>{searchTerms}</strong>&#038;meta=</em></p>
<p>де <em>{searchTerms}</em> - макрос, на місце якого підставляється введені в рядку браузера лексеми. І все ОК. А от в IE6 такого ключа нема. І там все робиться через дупу. <span id="more-54"></span>Саме цей романтичний шлях і буде далі описано&#8230;</p>
<p>Для визначення URL для підстановки в <em>Address bar</em> в разі, коли IE не може знайти протокол по якому потрібно працювати (ви не вказали його, а дреса не містить ніяких підказок, напр. у вигляді префікса &#8220;www.&#8221;) викликається COM-об&#8217;єкт, що реалізує інтерфейс <a href="http://msdn2.microsoft.com/en-us/library/ms631445.aspx">IURLSearchHook</a>. Цей інтерфейс має лише одну член-функцію: <a href="http://msdn2.microsoft.com/en-us/library/ms631448.aspx">Translate</a>. В комплекті з IE6 йде власна реалізація цього інтерфейсу, яка відкриває сторінку <em>auto.search.msn.com</em>. CLSID об&#8217;єкта, який відповідатиме за постачання URL прописано в ключі <em>HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\URLSearchHooks</em>. По замовучуванню використовується об&#8217;єкт з CLSID <em>{CFBFAE00-17A6-11D0-99CB-00C04FD64497}</em>. Для того, щоб встановити власний URL для пошуку за замовчуванням нам потрібно замінити його своєю реалізацію.</p>
<p>Для цього створюємо звичанйий проект ATL:</p>
<p><center><img src='http://graywolf.org.ua/wp-content/uploads/2007/08/ie-hook-1.jpg' alt='Customizing IE live search - Create ATL Project' /></center></p>
<p>Параметри залишаємо без змін. Далі в щойноствореному проекті через Class Wizard додаємо <em>ATL Simple Object</em> - клас, який і буде реалізацією інтерфейсу <a href="http://msdn2.microsoft.com/en-us/library/ms631445.aspx">IURLSearchHook</a>.</p>
<p><center><img src='http://graywolf.org.ua/wp-content/uploads/2007/08/ie-hook-2.jpg' alt='Customizing IE live search - Create ATL Simple Class' /></center></p>
<p>Даємо цьому класу якесь ім&#8217;я. Вкладку &#8220;Options&#8221; можна не чіпати і залишити все по дефолту.</p>
<p><center><img src='http://graywolf.org.ua/wp-content/uploads/2007/08/ie-hook-3.jpg' alt='Customizing IE live search - ATL Simple Class Wizard' /></center></p>
<p>Class Wizard зробив для нас практично всю брудну роботу і тепер можна, власне, дописувати необхідні дані.</p>
<p>Файл з описанням класу (в нашому прикладі Searcher.h) доводимо до наступного вигляду:</p>
<textarea name="code" class="cpp" cols="80" rows="10">// Searcher.h : Declaration of the CSearcher

#pragma once
#include "resource.h"       // main symbols

#include &lt;..\PlatformSDK\include\comdef.h&gt;
#include &lt;shlobj.h&gt;

// ISearcher
[
    object,
    uuid("A548953B-21A1-490F-A189-0F9FD714BDE2"),
    dual,	helpstring("ISearcher Interface"),
    pointer_default(unique)
]
__interface ISearcher : IDispatch
{
};

// CSearcher
[
    coclass,
    threading("apartment"),
    vi_progid("IESearchHook.Searcher"),
    progid("IESearchHook.Searcher.1"),
    version(1.0),
    uuid("94D618D6-E6E7-4EE9-B1B7-24C0B2327853"),
    helpstring("Searcher Class")
]
class ATL_NO_VTABLE CSearcher : 
    public ISearcher,
    public IURLSearchHook
{
public:
    CSearcher() {}

    DECLARE_PROTECT_FINAL_CONSTRUCT()

    BEGIN_COM_MAP(CSearcher)
        COM_INTERFACE_ENTRY(ISearcher)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(IURLSearchHook)
    END_COM_MAP()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }
	
    void FinalRelease() {}

public:
    STDMETHODIMP Translate(LPWSTR lpwszSearchURL, DWORD cchBufferSize)
    {
        LPWSTR wszURL = new WCHAR[cchBufferSize];
        ::LoadStringW(_AtlBaseModule.GetModuleInstance(), IDS_URL404, wszURL, cchBufferSize);
        wcsncat(wszURL, lpwszSearchURL, cchBufferSize);

        ZeroMemory(lpwszSearchURL, wcslen(wszURL));
        wcsncpy( lpwszSearchURL, wszURL, cchBufferSize);
        delete [] wszURL;
		        
        return S_OK;
    }
};
</textarea>
<p>Далі створюємо ресурс в String table з ідентифікатором <em>IDS_URL404</em> і змістом типу: <em>http://www.google.com/search?q=</em> (це пошук по гуглю) і збираємо продукт. Реєстрацію COM-об&#8217;єкта Visual Studio зробить за нас, але для того, щоб зареєструвати цю dll-бібліотеку на іншому компі потрібно буде виконати команду:</p>
<textarea name="code" class="cpp" cols="80" rows="10">regsvr32 IESearchHook.dll</textarea>
<p>До речі, по коду ще прошу звернути увагу на рядок:</p>
<textarea name="code" class="cpp" cols="80" rows="10">#include &lt;..\PlatformSDK\include\comdef.h&gt;</textarea>
<p>Справа в тому, що принаймні в Visual Studio .NET (2003) є два файли <em>comdef.h</em> і в одному з них не прописано GUID для <a href="http://msdn2.microsoft.com/en-us/library/ms631445.aspx">IURLSearchHook</a>. І тоді при компіляції в рядку:</p>
<textarea name="code" class="cpp" cols="80" rows="10">        COM_INTERFACE_ENTRY(IURLSearchHook)</textarea>
<p>може видаватись помилка типу:</p>
<textarea name="code" class="cpp" cols="80" rows="10">d:\Work\Other\IESearchHook\Searcher.h(49) : error C2787: 'IURLSearchHook' : no GUID has been associated with this object</textarea>
<p>Тому для того, щоб використовувати нормальний <em>comdef.h</em> пересвідчіться, що використовується саме той, який лежить в:</p>
<p><em>PATH_TO_VISUAL_STUDIO\Vc7\PlatformSDK\Include\</em>.</p>
<p>Ну і нарешті останній крок - це підстановка нашого COM-об&#8217;єкту замість експлорерівського. Для цього в ключі</p>
<p><em>HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\URLSearchHooks</em></p>
<p>видаляємо параметр, ім&#8217;я якого є CLSID поточного об&#8217;єкту, що видає рядок пошуку і створюємо параметр з іменем, рівним CLSID нашого об&#8217;єкту, обгонувши його в фігурні дужки. Для прикладу вище - це буде &#8220;{94D618D6-E6E7-4EE9-B1B7-24C0B2327853}&#8221;.</p>
<p>От і все. Запускаємо <em>Internet Explorer</em> і насолоджуємось пошуком в <em>Google</em> замість <em>Live Search</em> <img src='http://graywolf.org.ua/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> Цей спосіб випробувано для <em>Internet Explorer</em> версій 6 та 7. По ідеї має працювати починаючи з 4-го, але це не перевірялося.</p>
<p>Звісно, для реальної роботи функцію Translate треба буде дещо ускладнити, але то вже більш тривіальна справа.</p>
<p>За реалізацію цього завдання вчасно я мушу подякувати наявності наступних двох ресурсів:</p>
<ol>
<li><a href="http://answers.google.com/answers/threadview?id=305908">Google Answers: Change Autosearch URL in IE6</a>. Але спосіб описаний тут не зовсім працює <img src='http://graywolf.org.ua/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> Одна з помилок - це якраз описаний вище прикол з <em>comdef.h</em></li>
<li><a href="http://www.renpeicheng.com/html/2007-03/1653.html">Якийсь китайський ресурс</a>. Там добре, що була купа скрінів та багато коду і я інтуітивно здогадався в цій купі ієрогліфів в чому була лажа <img src='http://graywolf.org.ua/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
</ol>
<div class="meta">
<p><strong>Now playing: </strong>&nbsp;Slayer - [Christ Illusion] Cult<br/></p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://graywolf.org.ua/2007/08/30/%d0%b7%d0%b0%d0%bc%d1%96%d0%bd%d0%b0-url-%d0%b4%d0%bb%d1%8f-live-search-%d0%b2-ie/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Доступ до Event&#8217;у, що створюється в сервісі</title>
		<link>http://graywolf.org.ua/2007/08/23/%d0%b4%d0%be%d1%81%d1%82%d1%83%d0%bf-%d0%b4%d0%be-event%d1%83-%d1%89%d0%be-%d1%81%d1%82%d0%b2%d0%be%d1%80%d1%8e%d1%94%d1%82%d1%8c%d1%81%d1%8f-%d0%b2-%d1%81%d0%b5%d1%80%d0%b2%d1%96%d1%81%d1%96/</link>
		<comments>http://graywolf.org.ua/2007/08/23/%d0%b4%d0%be%d1%81%d1%82%d1%83%d0%bf-%d0%b4%d0%be-event%d1%83-%d1%89%d0%be-%d1%81%d1%82%d0%b2%d0%be%d1%80%d1%8e%d1%94%d1%82%d1%8c%d1%81%d1%8f-%d0%b2-%d1%81%d0%b5%d1%80%d0%b2%d1%96%d1%81%d1%96/#comments</comments>
		<pubDate>Thu, 23 Aug 2007 16:49:03 +0000</pubDate>
		<dc:creator>graywolf</dc:creator>
		
		<category><![CDATA[Code snippets]]></category>

		<guid isPermaLink="false">http://graywolf.org.ua/?p=25</guid>
		<description><![CDATA[Сьогодні мав кількагодинний геморой з написанням сервісу. Точніше завдяки кодпроджекту сам сервіс написався на раз (стаття про те як написати сервіс [англ.]), а от взаємодія його з експлореровським BHO вилилась в здоровецьку проблему. А все через кляті права доступу до об&#8217;єктів ядра. Проблема, власне, була в тому, що Windows service який мну написав запускається по [...]]]></description>
			<content:encoded><![CDATA[<p>Сьогодні мав кількагодинний геморой з написанням сервісу. Точніше завдяки кодпроджекту сам сервіс написався на раз (<a href="http://www.codeproject.com/system/windows_nt_service.asp">стаття про те як написати сервіс [англ.]</a>), а от взаємодія його з експлореровським BHO вилилась в здоровецьку проблему. А все через кляті права доступу до об&#8217;єктів ядра. Проблема, власне, була в тому, що Windows service який мну написав запускається по дефолту як і всі інші сервіси - від користувача SYSTEM. І от з тим-то і халепа, бо права на доступ до об&#8217;єктів ядра, що створються в сервісі виявляються спартанськими і звичанйому смертному, чи то пак додатку запущенному користувачем його не відкрити. Була купа ідей як його зробити, але зрештою як завжди допоміг Гугль, який вивів мене спочатку <a href="http://discuss.joelonsoftware.com/default.asp?joel.3.226319.5">сюди</a>, а потім і <a href="http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=1322">сюди</a>. В результаті і народилось рішення.</p>
<p><span id="more-25"></span><br />
Некрасиве, несек&#8217;юрне, але робоче:</p>
<textarea name="code" class="cpp" cols="80" rows="10">SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor( &#038;sd, SECURITY_DESCRIPTOR_REVISION );
SetSecurityDescriptorDacl( &#038;sd, TRUE, NULL, FALSE );

SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = false;

ATL::CEvent event;
event.Create( &#038;sa, 1, 0, c_eventName );</textarea>
<p>В результаті маємо об&#8217;єкт Event з доступом для службового користувача &#8220;Everyone&#8221;. Отаке. Можна, звісно, позаморачуватись з токенами, видирати ім&#8217;я залогіненого користувача і виставляти доступ лише для нього, але то такий геморой&#8230;
<div class="meta">
</div>
]]></content:encoded>
			<wfw:commentRss>http://graywolf.org.ua/2007/08/23/%d0%b4%d0%be%d1%81%d1%82%d1%83%d0%bf-%d0%b4%d0%be-event%d1%83-%d1%89%d0%be-%d1%81%d1%82%d0%b2%d0%be%d1%80%d1%8e%d1%94%d1%82%d1%8c%d1%81%d1%8f-%d0%b2-%d1%81%d0%b5%d1%80%d0%b2%d1%96%d1%81%d1%96/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
