<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>pamiętnik programisty &#187; tricky</title>
	<atom:link href="http://piotr.doniec.eu/devlog/tag/tricky/feed/" rel="self" type="application/rss+xml" />
	<link>http://piotr.doniec.eu/devlog</link>
	<description></description>
	<lastBuildDate>Wed, 28 Dec 2011 23:52:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Małoznany modyfikator [ dla scanf</title>
		<link>http://piotr.doniec.eu/devlog/2011/10/maloznany-modyfikator-dla-scanf/</link>
		<comments>http://piotr.doniec.eu/devlog/2011/10/maloznany-modyfikator-dla-scanf/#comments</comments>
		<pubDate>Wed, 19 Oct 2011 09:32:15 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[tricky]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=617</guid>
		<description><![CDATA[Funkcja scanf z biblioteki standardowej C umożliwia odczyt i parsowanie danych z stdin zgodnie z określonym formatem. Większość modyfikatorów jest opisana na stronie cppreference, która nomen omen pojawia się jako pierwsza po wpisaniu &#8222;scanf&#8221; w wyszukiwarce. Jak się jednak okazuje nie są to wszystkie dostępne modyfikatory. Brakuje jednego istotnego, który umożliwia np. czytanie standardowego wejścia [...]]]></description>
			<content:encoded><![CDATA[<p>Funkcja scanf z biblioteki standardowej C umożliwia odczyt i parsowanie danych z stdin zgodnie z określonym formatem. Większość modyfikatorów jest opisana na <a href="http://www.cplusplus.com/reference/clibrary/cstdio/scanf/">stronie cppreference</a>, która nomen omen pojawia się jako pierwsza po wpisaniu &#8222;scanf&#8221; w wyszukiwarce. Jak się jednak okazuje nie są to wszystkie dostępne modyfikatory. Brakuje jednego istotnego, który umożliwia np. czytanie standardowego wejścia póki składa się z prawidłowych/dozwolonych znaków &#8211; tym modyfikatorem jest &#8222;[ ]&#8222;. W nawiasach należy umieścić wszystkie znaki które sanf może odczytać. W przypadku napotkania znaku niewystępującego w zbiorze, scanf zaprzestaje dalszego działania.<br />
Możliwe jest również zdefiniowanie zakresu poprzez wykluczenie niektórych znaków, do tego celu należy użyć &#8222;^&#8221;. Dzięki temu przy wykorzystaniu scanf można odczytać całe zdanie ignorując białe znaki za wyjątkiem znaku końca linii:</p>
<pre class="brush: cpp">
char str[512];
scanf(&quot; [^\n]&quot;, &amp;str);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2011/10/maloznany-modyfikator-dla-scanf/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Methods for getting root access on Android phone</title>
		<link>http://piotr.doniec.eu/devlog/2011/04/methods-for-getting-root-access-on-android-phone/</link>
		<comments>http://piotr.doniec.eu/devlog/2011/04/methods-for-getting-root-access-on-android-phone/#comments</comments>
		<pubDate>Thu, 28 Apr 2011 13:43:41 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[tricky]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=611</guid>
		<description><![CDATA[Recently I got more interested in Android platform. I was wondering what are methods to obtain &#8222;root&#8221; rights. After few minutes of googling I found two possible solutions. First method make use of udev bug. Basically this service does not check source of message, so it is possible to run code on behalf of root [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I got more interested in Android platform. I was wondering what are methods to obtain &#8222;root&#8221; rights. After few minutes of googling I found two possible solutions.<br />
First method make use of udev bug. Basically this service does not check source of message, so it is possible to run code on behalf of root user. Second method is a bit more sophisticated in my opinion. It purpose is to block adb from dropping root privileges to normal user. It is done by creating maximum number of processes and then restarting adb.<br />
More detailed information an sample code can be found here: http://intrepidusgroup.com/insight/2010/09/android-root-source-code-looking-at-the-c-skills/</p>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2011/04/methods-for-getting-root-access-on-android-phone/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to migrate from Mambo 4.5.1 to Joomla 1.6</title>
		<link>http://piotr.doniec.eu/devlog/2011/03/how-to-migrate-from-mambo-4-5-1-to-joomla-1-6/</link>
		<comments>http://piotr.doniec.eu/devlog/2011/03/how-to-migrate-from-mambo-4-5-1-to-joomla-1-6/#comments</comments>
		<pubDate>Sat, 26 Mar 2011 22:39:33 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[Inne]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[issue]]></category>
		<category><![CDATA[joomla]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[tricky]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=584</guid>
		<description><![CDATA[My task was to migrate database from Mambo 4.5.1 to newest Joomla version which is now 1.6. I didn&#8217;t have to migrate any additional components data, just core functionality. At first I thought I will be an easy task, but then a few difficulties showed. Below I provide step which took me to happy end. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://piotr.doniec.eu/devlog/wp-content/uploads/2011/03/joomla-logo.png"><img class="alignleft size-medium wp-image-604" title="joomla-logo" src="http://piotr.doniec.eu/devlog/wp-content/uploads/2011/03/joomla-logo-300x205.png" alt="" width="210" height="144" /></a>My task was to migrate database from Mambo 4.5.1 to newest Joomla version which is now 1.6. I didn&#8217;t have to migrate any additional components data, just core functionality. At first I thought I will be an easy task, but then a few difficulties showed. Below I provide step which took me to happy end.<br />
<span id="more-584"></span></p>
<ol>
<li><strong>1. Copy database tables and Mambo code from remote server to local system</strong>. I used WAMP to do all migration. By doing that the site was still online, while I was doing some research. If for some reason you don&#8217;t have access to phpMyAdmin or any other database client, use <a href="http://sidu.sourceforge.net/sidu/">SIDU 3.2 DB Web GUI</a></li>
<li><strong>2. Convert SQL file to UTF8 encoding.</strong>You can do this using i.e. Notepad++ &#8211; use Convert to UTF8 (without BOM).<br />
Also change tables encoding to UTF8. This operation will cause problems with &#8216;ocp_core_acl_aro&#8217; table <code>"#1071, Specified key was too long; max key length is 1000 bytes"</code>. Rewrite it as below
<pre class="brush: sql">
CREATE TABLE `ocp_core_acl_aro` (
`aro_id` int(11) NOT NULL auto_increment,
`section_value` varchar(240) NOT NULL default &#039;0&#039;,
`value` varchar(240) NOT NULL default &#039;&#039;,
`order_value` int(11) NOT NULL default &#039;0&#039;,
`name` varchar(255) NOT NULL default &#039;&#039;,
`hidden` int(11) NOT NULL default &#039;0&#039;,
PRIMARY KEY  (`aro_id`),
UNIQUE KEY `ocp_gacl_section_value_value_aro` (`section_value`(100),`value`(75)),
UNIQUE KEY `section_value_value_aro` (`section_value`(100),`value`(75)),
KEY `hidden_aro` (`hidden`),
KEY `ocp_gacl_hidden_aro` (`hidden`)
) ENGINE=MyISAM AUTO_INCREMENT=13 DEFAULT CHARSET=utf8
</pre>
</li>
<li><strong>3. Migrate to Mambo 4.5.2</strong> Create local database for Mambo 4.5.2 and use utf8_general_ci for connection and comparison.  Download and extract Mambo 4.5.2 to webserver directory. Change db settings in configuration.php and apply sql script upgrade451to452.sql from installation\sql direcotry</li>
<li><strong>4. Install Joomla 1.5 but do not load sample data</strong></li>
<li><strong>5. Install mtwmigrator for Joomla 1.5</strong> You can download it here <a href="http://www.matware.com.ar/downloads/joomla/mtwmigrator/mtwmigrator-v0-2-1.html">mtwmigrator-v0-2-1</a>. Run component and go to Preference. Set db name, location, login and password. Select data you want to migrate and launch migration process. After this step you should have all data from Joomla 1.0 availbale in new installation on Joomla 1.5</li>
<li><strong>6. Migrate to Joomla 1.6 using jUpgrade. </strong>You can download it here <a href="http://www.matware.com.ar/downloads/joomla/jupgrade.html">jUpgrade</a>. All you have to do is to install it within Joomla 1.5 and start. If some problem occurs try enabling Debuging in jUpgrade</li>
<p>Now, you should have new installation of Joomla 1.6 created for you and available in jUpgrade dir in Joomla 1.5 directory. New tables were created in same database as Joomla 1.5, so depending on needs, final step might be to dump those tables and move to new, dedicated location.</ol>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2011/03/how-to-migrate-from-mambo-4-5-1-to-joomla-1-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Problem with timestamps in libnetfilter_queue solved</title>
		<link>http://piotr.doniec.eu/devlog/2010/12/problem-with-timestamps-in-libnetfilter_queue-solved/</link>
		<comments>http://piotr.doniec.eu/devlog/2010/12/problem-with-timestamps-in-libnetfilter_queue-solved/#comments</comments>
		<pubDate>Mon, 27 Dec 2010 21:45:09 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[issue]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[solution]]></category>
		<category><![CDATA[tricky]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=561</guid>
		<description><![CDATA[My BSc Thesis is to implement steganography algorithm that use VoIP packets as a transport. The main aim is to modify delay of RTP packets without noticeable impact on transmission quality. I create hidden channel by sending two packets that average delay is 20ms. For example if we send 1 packet 10ms after previous and [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://piotr.doniec.eu/devlog/wp-content/uploads/2010/12/netfilter-logo2.png"><img src="http://piotr.doniec.eu/devlog/wp-content/uploads/2010/12/netfilter-logo2.png" alt="" title="netfilter-logo2" width="265" height="72" class="alignleft size-full wp-image-576" /></a>My BSc Thesis is to implement steganography algorithm that use VoIP packets as a transport. The main aim is to modify delay of RTP packets without noticeable impact on transmission quality. I create hidden channel by sending two packets that average delay is 20ms. For example if we send 1 packet 10ms after previous and second 30ms after first the average delay is 20ms. Calling parties will not notice so small difference, but software should recognize such situation as sending the bit with value 1. When we want to send bit 0 we can just switch delays, then first packet will be sent after 30ms and another 10ms later. The time the packet was received is very important for Receiver. The network can add a random delay but Receiver should still be able to collect all sent bits.<br />
For implementation I used libnetfilter_queue and iptables. This two powerful tools are more than enough for my need. Everything was fine until and got to point where I had to read packet delay. Although libnetfilter_queue provide function for reading timestamp when packet was queued (nfq_get_timestamp) it&#8217;s not working without additional tweaks. For kernel performance reason timestamping network packets is by default disabled. After digging through kernel source I found functions responsible from toggling this setting, it&#8217;s a net_enable_timestamp() and net_disable_timestamp(). I had no idea how to execute each of them but MarkR from stackoverflow.org helped me. There is no need to enable timestamping globally for all packets instead it can be enabled for particular socket by using setsockopt. The call sequence is then setsockopt() -> sock_setsockopt() -> sock_enable_timestamp(&#8230;) -> net_enable_timestamp(). It is possible to get file descriptor connected with particular queue and treat it as it would be socket. This means that following code is valid and can be used to enable timestamping incoming packets:</p>
<pre class="brush: cpp">
int ena = 1;
if( setsockopt(queuefd, SOL_SOCKET, SO_TIMESTAMP, &amp;ena, sizeof(ena)) )
{
    SYS_LOG(E_WARNING, &quot;Unable to enable timestamping&quot;);
}
</pre>
<p>and then in queue handle function:</p>
<pre class="brush: cpp">
int handle_queue(struct nfq_q_handle *pQh, struct nfgenmsg *pNfmsg, struct nfq_data *pNfa, void *pData)
{
    struct nfqnl_msg_packet_hdr *ph;
    struct timeval tv;
    int id;

    ph = nfq_get_msg_packet_hdr(pNfa);
    if(ph)
    {
        id = ntohl(ph-&gt;packet_id);
    }

    nfq_get_timestamp(pNfa, &amp;tv);
    /* do sth. with read timestamp */

    return nfq_set_verdict(pQh, id, NF_ACCEPT, 0, NULL);
}
</pre>
<p>This is a solution for a issue, that as far as i know, have not been solved since this post:<br />
&#8222;So far the biggest issues I&#8217;ve run into are that marking doesn&#8217;t work in 2.6.15 (I think it should in 2.6.16), and I can&#8217;t seem to ever read the timestamp for a packet, no matter  hat hook it comes in on.  I&#8217;ve just been using gettimeofday for that for now.&#8221;<br />
<a href="http://lists.netfilter.org/pipermail/netfilter-devel/2006-February/023490.html">http://lists.netfilter.org/pipermail/netfilter-devel/2006-February/023490.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2010/12/problem-with-timestamps-in-libnetfilter_queue-solved/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Z C++ zagadka nr 5</title>
		<link>http://piotr.doniec.eu/devlog/2010/08/z-c-zagadka-nr-5/</link>
		<comments>http://piotr.doniec.eu/devlog/2010/08/z-c-zagadka-nr-5/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 20:22:26 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[tricky]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=549</guid>
		<description><![CDATA[Wrednie podchwytliwe zadanie czasami w tej czy innej postaci spotykane na różnych testach ze znajomości języka. Jaki będzie efekt wykonania poniższego programu: #include &#60;iostream&#62; int foo(int x, int y) { return x + y; } int main() { int z, k; z = 10; k = foo(z = 20, z += 1); std::cout &#60;&#60; k [...]]]></description>
			<content:encoded><![CDATA[<p>Wrednie podchwytliwe zadanie czasami w tej czy innej postaci spotykane na różnych testach ze znajomości języka.<br />
Jaki będzie efekt wykonania poniższego programu:</p>
<pre class="brush: cpp">
#include &lt;iostream&gt;

int foo(int x, int y)
{
    return x + y;
}

int main()
{
    int z, k;
    z = 10;
    k = foo(z = 20, z += 1);
    std::cout &lt;&lt; k &lt;&lt; std::endl;
}
</pre>
<p>Najłatwiej zweryfikować korzystając z kompilatora. Na rozważanie przyczyna takie czy innego wyniku nie warto poświęcać zbyt wiele czasu, ponieważ dodanie flagi -Wall rozwiewa wszystkie wątpliwości:</p>
<blockquote><p>
zadanie.cpp: In function &#8216;int main()&#8217;:<br />
zadanie.cpp:14: warning: operation on &#8216;z&#8217; may be undefined
</p></blockquote>
<p>Zatem poprawna odpowiedź na pytanie: &#8222;to zależy od kompilatora, sprzętu, systemu&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2010/08/z-c-zagadka-nr-5/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Z C++ zagadka nr 4</title>
		<link>http://piotr.doniec.eu/devlog/2010/07/z-c-zagadka-nr-4/</link>
		<comments>http://piotr.doniec.eu/devlog/2010/07/z-c-zagadka-nr-4/#comments</comments>
		<pubDate>Sun, 25 Jul 2010 12:50:24 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[common error]]></category>
		<category><![CDATA[tricky]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=532</guid>
		<description><![CDATA[Mając przedstawioną poniżej strukturę danych i kontener zawierający wskaźniki, wykonać operację/metodę methodA na rzecz obiektu obj_ posługując się iteratorem: class Foo { public: methodA() { printf(&#34;Wykonano...\n&#34;); } } struct data_t { int i_; Foo* obj_; } std::list&#60;data_t*&#62; data_; for(std::list&#60;data_t*&#62;::iterator i = data_.begin(); i != data_.end(); i++ ) { // operacje } W jaki sposób wykonać [...]]]></description>
			<content:encoded><![CDATA[<p>Mając przedstawioną poniżej strukturę danych i kontener zawierający wskaźniki, wykonać operację/metodę methodA na rzecz obiektu obj_ posługując się iteratorem:</p>
<pre class="brush: cpp">
class Foo {
public:
  methodA() {
    printf(&quot;Wykonano...\n&quot;);
  }
}

struct data_t {
  int i_;
  Foo* obj_;
}

std::list&lt;data_t*&gt; data_;

for(std::list&lt;data_t*&gt;::iterator i  = data_.begin(); i != data_.end(); i++ ) {
   // operacje
}
</pre>
<p>W jaki sposób wykonać blok operacji ? Możliwości mamy kilka:</p>
<pre class="brush: cpp">
/* 1 */ i-&gt;obj_-&gt;methodA();
/* 2 */ *i-&gt;obj_-&gt;methodA();
/* 3 */ (*i)-&gt;obj_-&gt;methodA();
</pre>
<p>Rozwiązanie zagadki jest proste, ale wymaga znajomości priorytetów operatorów. Pierwsze wywołania jest całkowicie błędne, ponieważ lista przecowuje wskaźniki do strkutury, a nie samą strukturę. Zatem należy najpier wyłuskać strukturę znajdującą się pod wskazywanym adresem i dopiero wtedy wykonać metodę. Okazuje się że rowiązania 2 również jest nie poprawne, właśnie ze względu na priorytety operatorów. Dopiero numer 3 daje zamierzony efekt. Na szczęście błąd ujawnia się na etapie kompilacji&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2010/07/z-c-zagadka-nr-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Uruchamianie metod klas w nowych wątkach w c++ i pthreads</title>
		<link>http://piotr.doniec.eu/devlog/2010/04/uruchamianie-metod-klas-w-nowych-watkach-w-c-i-pthreads/</link>
		<comments>http://piotr.doniec.eu/devlog/2010/04/uruchamianie-metod-klas-w-nowych-watkach-w-c-i-pthreads/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 10:47:17 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[pthreads]]></category>
		<category><![CDATA[qnx]]></category>
		<category><![CDATA[tricky]]></category>
		<category><![CDATA[wielowątkowość]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=471</guid>
		<description><![CDATA[Podczas pisania kolejnego projektu w języku c++ natknąłem się na interesujący problem. Program docelowo miał działać na systemie czasu rzeczywistego zatem jego celem było również zapoznanie z różnymi mechanizmami RTOS. Pierwszy problem pojawił się przy korzystaniu z mechanizmu wielowątkowości, pewnie byśmy się nie dowiedzieli o jego istnieniu gdybyśmy nie zdecydowali się na programowanie obiektowe, ale [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://piotr.doniec.eu/devlog/wp-content/uploads/2010/04/logo.gif" alt="qnx_rtos" title="qnx_rtos" width="106" height="45" class="alignright size-full wp-image-483" />Podczas pisania kolejnego projektu w języku c++ natknąłem się na interesujący problem. Program docelowo miał działać na systemie czasu rzeczywistego zatem jego celem było również zapoznanie z różnymi mechanizmami RTOS. Pierwszy problem pojawił się przy korzystaniu z mechanizmu wielowątkowości, pewnie byśmy się nie dowiedzieli o jego istnieniu gdybyśmy nie zdecydowali się na programowanie obiektowe, ale po kolei&#8230;<br />
<span id="more-471"></span><br />
Każdy kto programował w C++ korzystając z biblioteki Boost::Threads napewno wie że aby uruchomić metodę obiektu w nowym wątku wystarczy przeciążyć operator () i każdy obiekt takiej klasy zaczyna z powodzeniem udawać funkcję. Dzięki temu można taki obiekt przekazać do konstruktora boost::thread. Poniższy przykład obrazuje taką sposób działania:</p>
<pre class="brush: cpp">
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation.  William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided &quot;as is&quot; without express or implied warranty.

#include &lt;boost/thread/thread.hpp&gt;;
#include &lt;;boost/thread/xtime.hpp&gt;;
#include &lt;iostream&gt;;

struct thread_alarm
{
    thread_alarm(int secs) : m_secs(secs) { }
    void operator()()
    {
        boost::xtime xt;
        boost::xtime_get(&amp;xt, boost::TIME_UTC);
        xt.sec += m_secs;

        boost::thread::sleep(xt);

        std::cout &lt;&lt; &quot;alarm sounded...&quot; &lt;&lt; std::endl;
    }

    int m_secs;
};

int main(int argc, char* argv[])
{
    int secs = 5;
    std::cout &lt;&lt; &quot;setting alarm for 5 seconds...&quot; &lt;&lt; std::endl;
    thread_alarm alarm(secs);
    boost::thread thrd(alarm);
    thrd.join();
}
</pre>
<p>Jednak ten sposób nie działa w przypadku korzystania z natywnego mechanizmu wielowątkowości dostępnego w każdym systemie *nix. Biblioteka pthreads nie radzi sobie z wywołaniem przeciążonego operatora (). Problem trzeba było rozwiązać jak najszybciej, żeby projekt mógł ruszy dalej. Dlatego powstał ten sprytny &#8222;work-around&#8221; umożliwiający uruchomienie dowolnej metody obiektu w nowym wątku. Jest to właściwie funkcja proxy, takie proste a ułatwia życie:</p>
<pre class="brush: cpp">
template&lt;class T&gt;
struct ThreadParams
{
	T *obj;
	void *params;
};

template&lt;class T, void* (T::*method)(void*)&gt;
void* run_thread(void *params)
{
	ThreadParams&lt;T&gt; *t = static_cast&lt;ThreadParams&gt;&lt;T*&gt;(params);
	T* obj = static_cast&lt;T*&gt;(t-&gt;obj);
	(obj-&gt;*method)(t-&gt;params);
	return NULL;
}
</pre>
<p>Dodatkowy wkład pracy jaki należy włożyć aby wykorzystać powyższy kod ogranicza się właściwie tylko do wypełnienia struktury ThreadParams:</p>
<pre class="brush: cpp">
class Test
{
public:
	void* fun(void* params) {
	printf(&quot;Hello World! \n&quot;);
	printf(&quot;Params: %d\n&quot;, reinterpret_cast&lt;int&gt;(params));
	pthread_exit(NULL);
	}
 };

 int main() {

	pthread_t tid;
	void* status;
	Test test;
	ThreadParams&lt;Test&gt; params;

	params.obj = &amp;test;
	params.params = reinterpret_cast&lt;void&gt;(123);

	pthread_create(&amp;tid, NULL, run_thread&lt;Test, &amp;Test::fun&gt;, (void*)(&amp;params));
	pthread_join(tid, &amp;status);
 }
</pre>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2010/04/uruchamianie-metod-klas-w-nowych-watkach-w-c-i-pthreads/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SOAP w Pythonie</title>
		<link>http://piotr.doniec.eu/devlog/2010/01/soap-w-pythonie/</link>
		<comments>http://piotr.doniec.eu/devlog/2010/01/soap-w-pythonie/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 15:13:44 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[soap]]></category>
		<category><![CDATA[tricky]]></category>
		<category><![CDATA[webservices]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=396</guid>
		<description><![CDATA[Mimo że sam język jest uważany za potężny z dostępną dużą ilością bibliotek, to nie do koońca jest to prawda. SOAP w Pythonie niestety ale po prostu leży. Są 2 biblioteki umożliwiające tworzenie webserviców i tak naprawdę 2 które umożliwiają korzystanie z już utworzonych. Ja swoje próby rozpocząłem od soaplib, biblioteki która została porzucona przez [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-medium wp-image-400" title="soap_python" src="http://piotr.doniec.eu/devlog/wp-content/uploads/2010/01/soap_python-300x227.jpg" alt="soap_python" width="210" height="159" />Mimo że sam język jest uważany za potężny z dostępną dużą ilością bibliotek, to nie do koońca jest to prawda. SOAP w Pythonie niestety ale po prostu leży. Są 2 biblioteki umożliwiające tworzenie webserviców i tak naprawdę 2 które umożliwiają korzystanie z już utworzonych. Ja swoje próby rozpocząłem od soaplib, biblioteki która została porzucona przez twórców, ale w wyniku tzw. forków w miarę często pojawiają się nowe wersje. Niestety był to błąd.<br />
<span id="more-396"></span><br />
Nowe wersje od niezależnych twórców charakteryzują się większą bądź mniejszą ilością błędów. Najlepszą wersją okazała się wersja <strong>cuker soaplib</strong>, nie spełniała tylko 1 wymogu &#8211; generowania jakiegokolwiek kodu na podstawie WSDL. Jest to pewne nadużycie z mojej strony, biblioteka dostarczyła skrypt o nazwie wsdl2py, ale potrafił on poprawnie sparsować i zinterpretować plik wsdl utworzony tylko przez soaplib, co trzeba przyznać jest lekką &#8222;kichą&#8221;. Szkoda, biblioteka aktywnie rozwijana, wiązałem z nią spore nadzieje &#8211; odpadła.<br />
<strong>Suds</strong> to druga biblioteka związana z SOAP, aktywnie rozwijana, chwalona za łatwość korzystania, niestety przykłady dotyczą tylko tworzenia klinetów, serwerów poprostu tworzyć się nie da? W połączeniu z soaplib mogł by to być całkiem ciekawy duet.<br />
Biblioteka webserwisów dla Pythona <strong>ZSI</strong>,  w założeniu ma umożliwiać tworzenie i korzystanie z różnych webserviców, niestety projekt został porzucony w 2007 roku. Ale mimo to miłe zaskoczenie, dostarczane skrypty wsdl2py i wsdl2dispatch bez problemu radzą sobie z przykładowy wsdl dostępnymi w internecie. Tworzone są 3 pliki które potem można wykorzystać do implementacji serwera i klienta. Jednakże żeby nie było zbyt miło, serwer dostarczony z biblioteką jest jedno wątkowy. Jeśli operacje obsługi żądania jednego klienta są czasochłonne, to na ten czas serwer nie odpowiada na żądania innych klientów. Fatalna sprawa, ale! światełko w tunelu, ZSI można połączyć z Apache&#8217;m poprzez wykorzystanie mod_python ( oczywiście nie mogło być wersji dla python 2.6, na szczęście VS poradziło sobie z kompilacją ). Kolejna ślepa uliczka &#8211; jak bym tworzył stronę WWW. Przychodzi żądanie tworzone są wszystkie klasy a po zakończeniu obsługi usuwane &#8211; nie tak sobie wyobrażałem mój system rozproszony, zamiast w Pythonie mógłbym go napisać w PHP (sic!). Powrót do ZSI i eureka, ktoś bardziej doświadczony w tym języku dopisał kilka linii kodu do źródła i serwer stał się wielowątkowy! Połączenie idealne, wielowątkowość obsługi żądań, nie niszczenie wszystkiego po zakończeniu obsługi, możliwośc wypisywania komunikatów na ekran konsoli.<br />
Źródło rozwiązania: http://osdir.com/ml/python.pywebsvcs.general/2008-06/msg00019.html . Autor wykorzystał co prawda ZSI-2.1-a1, ale poprawka działa również na ostatniej stabilnej wersji ZSI-2.0</p>
<p>Na wszelki, skopiowany kod poprawki poniżej:</p>
<blockquote><p>&#8212; ZSI-2.1-a1/ZSI/ServiceContainer.py 2007-08-08 00:56:37.000000000 +0200<br />
+++ ServiceContainer.py 2008-06-19 13:50:11.000000000 +0200<br />
@@ -5,6 +5,7 @@</p>
<p>import urlparse, types, os, sys, cStringIO as StringIO, thread,re<br />
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer<br />
+from SocketServer import ThreadingMixIn<br />
from ZSI import ParseException, FaultFromException,<br />
FaultFromZSIException, Fault<br />
from ZSI import _copyright, _seqtypes, _get_element_nsuri_name, resolvers<br />
from ZSI import _get_idstr<br />
@@ -30,6 +31,7 @@<br />
SimpleWSResource<br />
SOAPRequestHandler<br />
ServiceContainer<br />
+ ThreadedServiceContainer<br />
&#8222;&#8221;"<br />
class NoSuchService(Exception): pass<br />
class UnknownRequestException(Exception): pass<br />
@@ -141,12 +143,16 @@<br />
return SendFault(FaultFromException(e, 0, sys.exc_info()[2]), **kw)</p>
<p>-def AsServer(port=80, services=()):<br />
+def AsServer(port=80, services=(), threaded=False):<br />
&#8221;&#8217;port &#8211;<br />
services &#8212; list of service instances<br />
+ threaded &#8212; in modo multithread ?<br />
&#8221;&#8217;<br />
address = (&#8221;, port)<br />
- sc = ServiceContainer(address, services)<br />
+ if threaded:<br />
+ sc = ThreadedServiceContainer(address, services)<br />
+ else:<br />
+ sc = ServiceContainer(address, services)<br />
sc.serve_forever()</p>
<p>@@ -467,6 +473,11 @@<br />
def removeNode(self, url):<br />
self._nodes.removeNode(url)</p>
<p>+class ThreadedServiceContainer(ThreadingMixIn, ServiceContainer):<br />
+ &#8221;&#8217;Multithreaded version of ServiceContainer.<br />
+ &#8221;&#8217;<br />
+ pass<br />
+</p>
<p>class SimpleWSResource(ServiceSOAPBinding):</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2010/01/soap-w-pythonie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HSSPOJ &#8211; zadanie które nie dawało mi spokoju</title>
		<link>http://piotr.doniec.eu/devlog/2010/01/hsspoj-zadanie-ktore-nie-dawalo-mi-spokoju/</link>
		<comments>http://piotr.doniec.eu/devlog/2010/01/hsspoj-zadanie-ktore-nie-dawalo-mi-spokoju/#comments</comments>
		<pubDate>Fri, 01 Jan 2010 19:37:11 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[Algorytmika]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[spoj]]></category>
		<category><![CDATA[teoria gier]]></category>
		<category><![CDATA[tricky]]></category>
		<category><![CDATA[twierdzenie Sprague-Grundy'ego]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=381</guid>
		<description><![CDATA[Zadanie z konkursu algorytmicznego dla uczniów szkół średnich. Zwróciłem na nie uwagę, gdyż współczynnik poprawnych rozwiązań wynosił lekko ponad 30%, a skoro to konkurs dla licealistów to powinienem sobie dać radę. I tu pierwszy szok, nic z tego&#8230; Wiedza jaką dysponowałem okazała się daleko nie wystarczająca, a próby znalezienia rozwiązania podanego na tacy spełzły na [...]]]></description>
			<content:encoded><![CDATA[<p>Zadanie z konkursu algorytmicznego dla uczniów szkół średnich. Zwróciłem na nie uwagę, gdyż współczynnik poprawnych rozwiązań wynosił lekko ponad 30%, a skoro to konkurs dla licealistów to powinienem sobie dać radę. I tu pierwszy szok, nic z tego&#8230; Wiedza jaką dysponowałem okazała się daleko nie wystarczająca, a próby znalezienia rozwiązania podanego na tacy spełzły na niczym. Co dodatkowo rozbudziło moją ciekawość to fakt że na forach poświęconych programowaniu, nikt nie szuka pomocy.<br />
Zadanie finalnie okazało się rozbudowaną grą Nim, ale bez znajomości jednego twierdzenia teorii gier prawdopodobnie siedziałbym na tym jeszcze dłuuuugo&#8230;<br />
Treść zadania dostępna pod adresem <a href="http://www.spoj.pl/HSPLARCH/problems/HS09GAME/">http://hs.spoj.pl/problems/HS09GAME/</a><br />
<span id="more-381"></span><br />
Wspomniane twierdzenie to Twierdzenie Sprague-Grundy&#8217;ego. Gra przestawiona w zadaniu spełnia wszystkie założenia pozwalające na skorzystanie z twierdzenia. W połączeniu z dokładnie omówioną optymalną strategią, opisem pozycji wygrywających i przegrywających w grze Nim, pierwszą część zadania można rozwiązać w zaledwie 9 liniach</p>
<pre class="brush: python">
# gry - lista skladajaca sie z list reprezentujacych gre. Kazda reprezentacja
# gry to kolejna lista zaiwerajaca ilosc &#039;kijkow&#039; na kolejnych stosach
def graj(gry):
    sg = (0, 0, 1, 1, 2, 2, 3)
    for gra in gry:
        g = []
        reszty = []
        for stos in gra:
            reszta = int(stos)%7
            g.append(sg[reszta])
            reszty.append(reszta)
        wynik = reduce(lambda x,y: x^y, g)

        if wynik :
            print &quot;Julia wins.&quot;
        else :
            print &quot;Robert wins.\n&quot;
</pre>
<p>Lekki problem pojawia się przy ustalaniu ruchu wygrywającego. Nie wiem czy istnieje jakieś szybsze rozwiązanie niż takie trochę brute-force&#8217;owe która ja wykorzystałem. Polega ono na stwierdzeniu na jakiej pozycji ( wygrywającej czy przegrywającej ) znalazł by się gracz gdyby nie było jednego stosiku, a następnie obliczeniu czy da się odjąć taką liczbę patyczków żeby zostawić przeciwnika na pozycji przegrywającej.<br />
Dodatkowo oprócz wskazania ruchu wygrywającego należy wskazać ten podczas którego bierze się najwięcej patyczków ze stosu o najmniejszym numerze, co w lekki sposób komplikuje sprawę.:</p>
<pre class="brush: python">
        stos_wygrywajacy = 0;
        licznik = 0
        blokada_5 = False
        blokada_3 = False

        # odwrocenie list, sprawdzanie od konca
        gra_rev = gra[:]
        gra_rev.reverse()

        g_rev = g[:]
        g_rev.reverse()

        reszty.reverse()
        for reszta in reszty:
            # lista reszt bez kolejnych stosow
            tmpr = reszty[:]
            tmpr.pop(licznik)

            # xor wartosci f. Sprague-Grundy&#039;ego
            # bez kolejnych stosow
            tmpg = g_rev[:]
            tmpg.pop(licznik)
            tmpw = reduce(lambda x,y: x^y, tmpg ,0)

            if sg[reszta-5] == tmpw and int(gra_rev[licznik]) &gt;= 5:
                wygrywajacy = 5
                stos_wygrywajacy = len(reszty) - licznik
                blokada_5 = True
            elif sg[reszta-3] == tmpw and int(gra_rev[licznik]) &gt;= 3 and blokada_5 == False:
                wygrywajacy = 3
                stos_wygrywajacy = len(reszty) - licznik
                blokada_3 = True
            elif sg[reszta-2] == tmpw and int(gra_rev[licznik]) &gt;= 2 and blokada_5 == False and blokada_3 == False:
                wygrywajacy = 2
                stos_wygrywajacy = len(reszty) - licznik

            licznik += 1
</pre>
<p>Jeśli ktoś zna szybsze rozwiązanie chętnie je przeanalizuję <img src='http://piotr.doniec.eu/devlog/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
Zaznaczam, że nie dam sobie głowy uciąć że algorytm jest poprawny, bo nie ma już możliwości zgłoszenia rozwiązania &#8211; upłynęły terminy.</p>
<p><strong><em>EDIT</em></strong>:<br />
Lekko poprawiona wersja, działa trochę szybciej, natomiast i tak nie umożliwia zdobycia maximum punktów. Jesli nie ma jakiejś sztuczki na ruch wygrywający, a podejrzewam że coś jest, to lepiej zakodzić to w C&#8230;</p>
<pre class="brush: python">
        stos_wygrywajacy = 0
        blokada_3 = False
        blokada_2 = False
        licznik = 0
        for reszta in reszty :
            tmpg = g[:]
            tmpg.pop(licznik)
            tmpw = reduce(lambda x,y: x^y, tmpg, 0)

            if sg[reszta-5] == tmpw and int(gra[licznik]) &gt;= 5:
                wygrywajacy = 5
                stos_wygrywajacy = licznik + 1
                break
            elif sg[reszta-3] == tmpw and int(gra[licznik]) &gt;= 3 and blokada_3 == False:
                wygrywajacy = 3
                stos_wygrywajacy = licznik + 1
                blokada_3 = True
            elif sg[reszta-2] == tmpw and int(gra[licznik]) &gt;= 2 and blokada_3 == False and blokada_2 == False:
                wygrywajacy = 2
                stos_wygrywajacy = licznik + 1
                blokada_2 = True
            licznik += 1
</pre>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2010/01/hsspoj-zadanie-ktore-nie-dawalo-mi-spokoju/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Przezroczyste okienka z WinAPI</title>
		<link>http://piotr.doniec.eu/devlog/2009/10/przezroczyste-okienka-z-winapi/</link>
		<comments>http://piotr.doniec.eu/devlog/2009/10/przezroczyste-okienka-z-winapi/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 12:24:08 +0000</pubDate>
		<dc:creator>pejotr</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[tricky]]></category>
		<category><![CDATA[winapi]]></category>

		<guid isPermaLink="false">http://piotr.doniec.eu/devlog/?p=270</guid>
		<description><![CDATA[Wraz z pojawieniem się systemu Windows 2000, pojawiły się nowe funkcje systemowego API. Jedną z nich jest możliwość tworzenia okien o dowolnym stopniu przezroczystości. Efekt jest dość ciekawy i sporo programów ma możliwość ustawienia przezroczystości własnego okienka. Moim celem było umożliwienie sterowania przezroczystością okien centralnie z jednego programu i to nie zależnie od tego czy [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-339 alignleft" title="transparent_windows2" src="http://piotr.doniec.eu/devlog/wp-content/uploads/2009/10/transparent_windows21.jpg" alt="Przezroczyste okna z winAPI" width="244" height="220" />Wraz z pojawieniem się systemu Windows 2000, pojawiły się nowe funkcje systemowego API. Jedną z nich jest możliwość tworzenia okien o dowolnym stopniu przezroczystości. Efekt jest dość ciekawy i sporo programów ma możliwość ustawienia przezroczystości własnego okienka. Moim celem było umożliwienie sterowania przezroczystością okien centralnie z jednego programu i to nie zależnie od tego czy okno takie zostało do tego przystosowane czy też nie. Po przeczytaniu tego wpisu, każdy samodzielnie będzie mógł napisać podobną aplikację</p>
<p><span id="more-270"></span></p>
<p>Aby istniała możliwość ustawiania przezroczystości dla okna, musi być ono utworzone w sposób do tego przystosowany. Wystarczy skorzystać z innej funkcji tworzącej okno, nie <code>CreateWindow</code>, a <code>CreateWindowEx</code><br />
[cc lang="c"]<br />
HWND CreateWindowEx(<br />
  DWORD dwExStyle,<br />
  LPCTSTR lpClassName,<br />
  LPCTSTR lpWindowName,<br />
  DWORD dwStyle,<br />
  int x,<br />
  int y,<br />
  int nWidth,<br />
  int nHeight,<br />
  HWND hWndParent,<br />
  HMENU hMenu,<br />
  HINSTANCE hInstance,<br />
  LPVOID lpParam<br />
);<br />
[/cc]<br />
To co umożliwia później modyfikacje przezroczystości jest ukryte w ramach dodatkowego stylu okna, podawanego poprzez argument <code>dwExStyle</code>. Lista dopuszczalnych wartości jest długa, ale warto się z nią zapoznać. W tym konkretnym przypadku należy zainteresować się wartością <code>WS_EX_LAYERED</code>, utworzone wtedy okno będzie tzw. Layered Window, które obsługuje modyfikacje przezroczystości. Do ustawienia nowej wartości kanału alpha służy <code>SetLayeredWindowAttributes(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWROD dwFlags)</code> &#8211; szczegóły w dokumentacji.<br />
Pełny kod tworzący przykładowe, półprzezroczyste okno:<br />
[cc lang="c"]<br />
#include <windows.h></p>
<p>LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);</p>
<p>int WINAPI WinMain(HINSTANCE hInstance,	HINSTANCE hPrevInstance,<br />
LPSTR lpCmdLine, int nCmdShow)<br />
{<br />
  MSG msg;<br />
  HWND hwnd;<br />
  WNDCLASSEX wcx;</p>
<p>  wcx.cbSize = sizeof(wcx);<br />
  wcx.style = CS_HREDRAW | CS_VREDRAW;<br />
  wcx.lpfnWndProc = WndProc;<br />
  wcx.cbClsExtra = 0;<br />
  wcx.cbWndExtra = 0;<br />
  wcx.hInstance = hInstance;<br />
  wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);<br />
  wcx.hCursor = LoadCursor(NULL, IDC_ARROW);<br />
  wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);<br />
  wcx.lpszMenuName = (LPCSTR)&#8221;MainMenu&#8221;;<br />
  wcx.lpszClassName = (LPCSTR)&#8221;MainWClass&#8221;;<br />
  wcx.hIconSm = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(5), IMAGE_ICON,<br />
  GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), (UINT)LR_DEFAULTCOLOR);</p>
<p>  RegisterClassEx(&#038;wcx);</p>
<p>  hwnd = CreateWindowEx(WS_EX_LAYERED, (LPCSTR)&#8221;MainWClass&#8221;, (LPCSTR)&#8221;Sample&#8221;, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, (HWND)NULL,  (HMENU)NULL, hInstance, (LPVOID) NULL);</p>
<p>  ShowWindow(hwnd, nCmdShow);<br />
  SetLayeredWindowAttributes(hwnd, 0, 180, LWA_ALPHA);<br />
  UpdateWindow(hwnd);</p>
<p>  while(GetMessage(&#038;msg, NULL,  0, 0))<br />
  {<br />
    TranslateMessage(&#038;msg);<br />
    DispatchMessage(&#038;msg);<br />
  }</p>
<p>  return msg.wParam;<br />
}</p>
<p>LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)<br />
{<br />
  switch(uMsg)<br />
  {<br />
    case WM_CREATE:<br />
      return 0;</p>
<p>    case WM_PAINT:<br />
      return 0;</p>
<p>    case WM_DESTROY:<br />
      PostQuitMessage(0);<br />
      return 0;</p>
<p>    default:<br />
      return DefWindowProc(hwnd, uMsg, wParam, lParam);<br />
  }<br />
  return 0;<br />
}<br />
[/cc]</p>
<p>To co należy zrobić, aby kontrolować przezroczystość okien innych niż własne przedstawia się następująco:</p>
<ol>
<li>1. Pobrać wszystkie otwarte okna typu top-level</li>
<li>2. Nadać oknom styl <code>dwExStyle</code></li>
<li>3. Zmienić wartość kanału alpha</li>
</ol>
<p><strong>1. Pobrać wszystkie otwarte okna typu top-level</strong><br />
Dobrym pomysłem wydaje się pobranie uchwytu do rodzica wszystkich okien(Desktop/Pulpit) i przejście w pętli po liście jego dzieci (jak wiadomo każde okno ma kilka przydatnych wskaźników, między innymi do okna-brata). Mogłoby to wyglądać tak:<br />
[cc lang="c"]<br />
HWND hDesktop = GetDesktopWindow();<br />
HWND hChild = GetWindow(hDesktop, GW_CHILD);<br />
HWND hTemp;<br />
/* &#8230; */<br />
while(hTemp != GetWindow(hChild, GW_HWNDLAST))<br />
{<br />
  /* &#8230; */<br />
  hTemp = GetWindow(hChild, GW_HWNDNEXT);<br />
}<br />
[/cc]<br />
Pomysł <strong>zły</strong> ! Okazuje się że taka pętla może działać w nieskończoność. Wzmianaka na temat takiego przypadku znajduje się nawet w dokumentacji. Dlatego należy wykorzystać inny sposób, polegający na użyciu funkcji <code>BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)</code>:<br />
[cc lang="c"]<br />
EnumWindows(EnumWindowsProc, NULL);<br />
/* &#8230; */<br />
BOOL CALLBACK EnumWindowsProc(HWND hwndChild, LPARAM lParam)<br />
{<br />
  char buffer[100];</p>
<p>  int count = GetWindowText(hwndChild, buffer, 100);<br />
  if(count &#038;&#038; IsWindowVisible(hwndChild))<br />
  {<br />
    /* &#8230; */<br />
  }<br />
  return TRUE;<br />
}<br />
[/cc]</p>
<p><strong>2. Nadać oknom styl <code>dwExStyle</code></strong><br />
Wydaje się najtrudniejsze, przecież dodatkowy styl należy podać przy tworzeniu okna, a okna które widzimy zostały już przecież utworzone. Na szczęście z pomocą przychodzi funkcja <code>LONG SetWindowLong(HWND hWnd, int iIndex, LONG dwNewLong)</code>:<br />
[cc lang="c"]<br />
SetWindowLong(hwndChild, GWL_EXSTYLE, WS_EX_LAYERED);<br />
[/cc]</p>
<p><strong>3. Zmienić wartość kanału alpha</strong><br />
Bardziej uważni czytelnicy już na pewno wiedzą jak wygląda zestaw parametrów i jak skorzystać z <code>SetLayeredWindowAttributes</code>. Wykorzystanie pokazane 3 listingi wyżej, przy okazji tworzenia &#8222;własnego&#8221; przezroczystego okna.</p>
<p>I to tyle  tym temacie, wypada jeszcze stworzyć GUI, może obsługę tray&#8217;a. Program wydaje się &#8222;magiczny&#8221; a korzysta raptem z 4 funkcji API systemowego.</p>
]]></content:encoded>
			<wfw:commentRss>http://piotr.doniec.eu/devlog/2009/10/przezroczyste-okienka-z-winapi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

