<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-453740415575159373</id><updated>2012-02-01T01:05:30.915+08:00</updated><category term='MP4'/><category term='GDM'/><category term='C'/><category term='Google Docs'/><category term='Kernel'/><category term='Essential COM'/><category term='Windows'/><category term='GDI'/><category term='Programming'/><category term='C++'/><category term='Shell'/><category term='GObject'/><category term='Graphics'/><category term='CIM'/><category term='iPod'/><category term='Annotation'/><category term='GFW'/><category term='Property'/><category term='Apache'/><category term='Miscellaneous'/><category term='Transparency'/><category term='BIOS'/><category term='SSH'/><category term='QTerm'/><category term='CentOS'/><category term='C++0x'/><category term='UML'/><category term='WebDAV'/><category term='COM'/><category term='Java'/><category term='Gnome'/><category term='Symbian'/><category term='ADO.NET'/><category term='C#'/><category term='Vim'/><category term='Unicode'/><category term='MSVC'/><category term='WCF'/><category term='Lucid'/><category term='Linux'/><category term='OOP'/><category term='Translucency'/><category term='Qt'/><category term='Tools'/><category term='Debug'/><category term='Ubuntu'/><category term='Bash'/><category term='SVN'/><category term='Boost'/><category term='.NET'/><title type='text'>逆さまの蝶</title><subtitle type='html'>gonwan's Technique Blog</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>94</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5038473971414147057</id><published>2011-10-04T20:17:00.001+08:00</published><updated>2011-10-04T20:17:28.402+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><category scheme='http://www.blogger.com/atom/ns#' term='Bash'/><title type='text'>Learning Bash Scripts (3)</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; This post covers the loop usage of bash shell. &lt;b&gt;NOTE&lt;/b&gt;: read inline comments carefully :)&lt;br /&gt;1. &lt;b&gt;for loop&lt;/b&gt;:&lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# loop list, last value remains&lt;br /&gt;for test in Alabama Alaska Arizona Arkansas California Colorado&lt;br /&gt;do&lt;br /&gt;    echo The next state is $test&lt;br /&gt;done&lt;br /&gt;echo "The last state we visited was $test"&lt;br /&gt;test=Connecticut&lt;br /&gt;echo "Wait, now we're visiting $test"&lt;br /&gt;&lt;br /&gt;# using escape or quote&lt;br /&gt;for test in I don\'t know if "this'll" work&lt;br /&gt;do&lt;br /&gt;    echo "word: $test"&lt;br /&gt;done&lt;br /&gt;&lt;br /&gt;# loop variable &amp;amp; files&lt;br /&gt;states="Alabama Alaska Arizona Arkansas Colorado Connecticut Delaware Florida Georgia"&lt;br /&gt;statesfile=states.txt&lt;br /&gt;for state in $states; do&lt;br /&gt;    echo $state &amp;gt;&amp;gt; $statesfile&lt;br /&gt;done&lt;br /&gt;for state in `cat $statesfile`; do&lt;br /&gt;    echo "Visit beautiful $state"&lt;br /&gt;done&lt;br /&gt;rm $statesfile&lt;br /&gt;&lt;br /&gt;# loop directory&lt;br /&gt;for file in ~/.b*; do&lt;br /&gt;    if [ -d "$file" ]; then&lt;br /&gt;        echo "$file is a directory"&lt;br /&gt;    elif [ -f "$file" ]; then&lt;br /&gt;        echo "$file is a file"&lt;br /&gt;    else&lt;br /&gt;        echo "$file doesn't exist"&lt;br /&gt;    fi&lt;br /&gt;done&lt;br /&gt;&lt;br /&gt;# c-style syntax&lt;br /&gt;for (( i = 1; i &amp;lt;= 10; i++ )); do&lt;br /&gt;    echo "The next number is $i"&lt;br /&gt;done&lt;br /&gt;&lt;br /&gt;# IFS (internal field separator) to separator string&lt;br /&gt;IFSOLD=$IFS&lt;br /&gt;IFS=$'\n'&lt;br /&gt;for entry in `cat /etc/passwd`; do&lt;br /&gt;    echo "Values in $entry:"&lt;br /&gt;    IFS=:&lt;br /&gt;    for value in $entry; do&lt;br /&gt;        echo "  $value"&lt;br /&gt;    done&lt;br /&gt;done&lt;br /&gt;IFS=$IFSOLD&lt;/pre&gt;2. &lt;b&gt;while loop&lt;/b&gt;: &lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;var1=10&lt;br /&gt;while [ $var1 -gt 0 ]; do&lt;br /&gt;    echo $var1&lt;br /&gt;    var1=$[ $var1 - 1 ]&lt;br /&gt;done&lt;/pre&gt;3. &lt;b&gt;until loop&lt;/b&gt;: &lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;var1=100&lt;br /&gt;until [ $var1 -eq 0 ]; do&lt;br /&gt;    echo $var1&lt;br /&gt;    var1=$[ $var1 - 25 ]&lt;br /&gt;done&lt;/pre&gt;4. &lt;b&gt;break &amp;amp; continue&lt;/b&gt; &lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# break&lt;br /&gt;for (( a = 1; a &amp;lt; 4; a++ )); do&lt;br /&gt;    echo "Outer loop: $a"&lt;br /&gt;    for (( b = 1; b &amp;lt; 100; b++ )); do&lt;br /&gt;        if [ $b -eq 5 ]; then&lt;br /&gt;            break&lt;br /&gt;        fi&lt;br /&gt;        echo "Inner loop: $b"&lt;br /&gt;    done&lt;br /&gt;done&lt;br /&gt;&lt;br /&gt;# break outer loop&lt;br /&gt;for (( a = 1; a &amp;lt; 4; a++ )); do&lt;br /&gt;    echo "Outer loop: $a"&lt;br /&gt;    for (( b = 1; b &amp;lt; 100; b++ )); do&lt;br /&gt;        if [ $b -eq 5 ]; then&lt;br /&gt;            break 2&lt;br /&gt;        fi&lt;br /&gt;        echo "Inner loop: $b"&lt;br /&gt;    done&lt;br /&gt;done&lt;br /&gt;&lt;br /&gt;# continue outer loop&lt;br /&gt;for (( a = 1; a &amp;lt;= 5; a++ )); do&lt;br /&gt;    echo "Iteration $a:"&lt;br /&gt;    for (( b = 1; b &amp;lt; 3; b++ )); do&lt;br /&gt;        if [ $a -gt 2 ] &amp;amp;&amp;amp; [ $a -lt 4 ]; then&lt;br /&gt;            continue 2&lt;br /&gt;        fi&lt;br /&gt;        var3=$[ $a * $b ]&lt;br /&gt;        echo "  The result of $a * $b is $var3"&lt;br /&gt;    done&lt;br /&gt;done&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; There may be times when you're in an inner loop but need to stop the outer loop. The break command includes a single command line parameter value: &lt;code&gt;break n&lt;/code&gt; where n indicates the level of the loop to break out of. By default, n is 1, indicating to break out of the current loop. If you set n to a value of 2, the break command will stop the next level of the outer loop.&lt;br /&gt;&lt;br /&gt;5. &lt;b&gt;redirect &amp;amp; pipe&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Finally, you can either pipe or redirect the output of a loop within your shell script.&lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;testfile=testloop.txt&lt;br /&gt;for (( a = 1; a &amp;lt; 10; a++ )); do&lt;br /&gt;    echo "The number is $a"&lt;br /&gt;done &amp;gt; $testfile&lt;br /&gt;echo "The command is finished."&lt;br /&gt;cat $testfile&lt;br /&gt;rm $testfile&lt;/pre&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5038473971414147057?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5038473971414147057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5038473971414147057&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5038473971414147057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5038473971414147057'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/10/learning-bash-scripts-3.html' title='Learning Bash Scripts (3)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5504896508839934731</id><published>2011-10-04T17:13:00.000+08:00</published><updated>2011-10-04T17:13:37.832+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><category scheme='http://www.blogger.com/atom/ns#' term='Bash'/><title type='text'>Learning Bash Scripts (2)</title><content type='html'>1. &lt;b&gt;Comments&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; When creating a shell script file, you must specify the shell you are using in the first line of the file. The format for this is:&lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;# This script displays the date and who's logged on&lt;br /&gt;date&lt;br /&gt;who&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In a normal shell script line, the pound sign(#) is used as a comment line. A comment line in a shell script isn't processed by the shell. However, the first line of a shell script file is a special case, and the pound sign followed by the exclamation point tells the hell what shell to run the script under (yes, you can be using a bash shell and run your script using another shell).&lt;br /&gt;&lt;br /&gt;2. &lt;b&gt;Display&lt;/b&gt;:&lt;br /&gt;The &lt;code&gt;echo&lt;/code&gt; command can display a simple text string if you add the string following the command.&lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;# basic usage&lt;br /&gt;echo This is a test.&lt;br /&gt;echo "Let's see if this'll work"&lt;br /&gt;# environment variables&lt;br /&gt;echo "User info for user: $USER"&lt;br /&gt;echo UID: $UID&lt;br /&gt;echo HOME: $HOME&lt;br /&gt;echo "The cost of the item is \$15"&lt;br /&gt;# user variables&lt;br /&gt;days=10&lt;br /&gt;guest="Katie"&lt;br /&gt;echo "$guest checked in $days days ago"&lt;br /&gt;days=5&lt;br /&gt;guest="Jessica"&lt;br /&gt;echo "$guest checked in $days days ago"&lt;br /&gt;# backtip&lt;br /&gt;testing=`date`&lt;br /&gt;echo "The date and time are: " $testing&lt;br /&gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The &lt;code&gt;echo&lt;/code&gt; command uses either double or single quotes to delineate text strings. If you use them within your string, you need to use one type of quote within the text and the other type to delineate the string.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Notice that the environment variables in the &lt;code&gt;echo&lt;/code&gt; commands are replaced by their current values when the script is run. Also notice that we were able to place the $USER system variable within the double quotation marks in the first string, and the shell script was still able to figure out what we meant.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You may also see variables referenced using the format ${variable}. The extra braces around the variable name are often used to help identify the variable name from the dollar sign.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; User variables can be any text string of up to 20 letters, digits, or an underscore character. User variables are case sensitive, so the variable Var1 is different from the variable var1. This little rule often gets novice script programmers in trouble.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Values are assigned to user variables using an equal sign. No spaces can appear between the variable, the equal sign, and the value (another trouble spot for novices). Here are a few examples of assigning values to user variables.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The shell script automatically determines the data type used for the variable value. Variables defined within the shell script maintain their values throughout the life of the shell script but are deleted when the shell script completes.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Just like system variables, user variables can be referenced using the dollar sign. It's important to remember that when referencing a variable value you use the dollar sign, but when referencing the variable to assign a value to it, you do not use the dollar sign.&lt;br /&gt;&amp;nbsp; &amp;nbsp; The backtick allows you to assign the output of a shell command to a variable.&lt;br /&gt;&lt;br /&gt;3. &lt;b&gt;Redirect I/O&lt;/b&gt;:&lt;br /&gt;&amp;gt;: output redirect&lt;br /&gt;&amp;gt;&amp;gt;: output redirect append data &lt;br /&gt;&amp;lt;: input redirect&lt;br /&gt;&amp;lt;&amp;lt;: inline input redirect&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ wc &amp;lt;&amp;lt; EOF&lt;br /&gt;&amp;gt; test string 1&lt;br /&gt;&amp;gt; test string 2&lt;br /&gt;&amp;gt; test string 3&lt;br /&gt;&amp;gt; EOF&lt;br /&gt;    3    9    42&lt;br /&gt;$ &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The inline input redirection symbol is the double less-than symbol (&amp;lt;&amp;lt;). Besides this symbol, you must specify a text marker that delineates the beginning and end of the data used for input. You can use any string value for the text marker, but it must be the same at the beginning of the data and the end of the data.&lt;br /&gt;&lt;br /&gt;4. &lt;b&gt;Math Expression&lt;/b&gt;:&lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;var1=10&lt;br /&gt;var2=3&lt;br /&gt;var3=`expr $var1 \* $var2`&lt;br /&gt;var4=$[$var1 * $var2]&lt;br /&gt;var5=`expr $var1 / $var2`&lt;br /&gt;var6=$[$var1 / $var2]&lt;br /&gt;var7=`echo "scale=3; $var1 / $var2" | bc`&lt;br /&gt;echo The result is $var3&lt;br /&gt;echo The result is $var4&lt;br /&gt;echo The result is $var5&lt;br /&gt;echo The result is $var6&lt;br /&gt;echo The result is $var7&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The &lt;code&gt;expr&lt;/code&gt; command allowed the processing of equations from the command line. Note the spaces around operator is necessary. Escape character(backslash) is used to identify any characters that may be misinterpreted by the shell before being passed to the &lt;code&gt;expr&lt;/code&gt; command.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Bash also provides a much easier way of performing mathematical equations. In bash, when assigning a mathematical value to a variable, you can enclose the mathematical equation using a dollar sign and square brackets ($[ operation ]).&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The bash shell mathematical operators support only integer arithmetic. The most popular solution uses the built-in bash calculator, called &lt;code&gt;bc&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;5. &lt;b&gt;Structured Commands&lt;/b&gt;:&lt;br /&gt;a) &lt;b&gt;if/else&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The bash shell &lt;i&gt;if&lt;/i&gt; statement runs the command defined on the &lt;i&gt;if&lt;/i&gt; line. If the exit status of the command is zero (the command completed successfully), the commands listed under the &lt;i&gt;then&lt;/i&gt; section are executed. If the exit status of the command is anything else, the then commands aren't executed, and the bash shell moves on to the next command in the script. &lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;user=gonwan&lt;br /&gt;user2=test2&lt;br /&gt;user3=test3&lt;br /&gt;# if-then&lt;br /&gt;if grep $user /etc/passwd; then&lt;br /&gt;    echo "The bash files for user $user are:"&lt;br /&gt;    ls -a /home/$user/.b*&lt;br /&gt;fi&lt;br /&gt;# if-then-else&lt;br /&gt;if grep $user2 /etc/passwd; then&lt;br /&gt;    echo "The bash files for user $user2 are:"&lt;br /&gt;    ls -a /home/$user2/.b*&lt;br /&gt;else&lt;br /&gt;    echo "The user name $user2 does not exist on this system"&lt;br /&gt;fi&lt;br /&gt;#if-then-elif-then-else&lt;br /&gt;if grep $user3 /etc/passwd; then&lt;br /&gt;    echo "The bash files for user $user3 are:"&lt;br /&gt;    ls -a /home/$user3/.b*&lt;br /&gt;elif grep $user2 /etc/passwd; then&lt;br /&gt;    echo "The bash files for user $user2 are:"&lt;br /&gt;    ls -a /home/$user2/.b*&lt;br /&gt;else&lt;br /&gt;    echo "The user name $user2 and $user3 does not exist on this system"&lt;br /&gt;fi&lt;/pre&gt;b) &lt;b&gt;test&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The &lt;code&gt;test&lt;/code&gt; command provides a way to test different conditions in an &lt;i&gt;if-then&lt;/i&gt; statement. If the condition listed in the test command evaluates to true, the test command exits with a zero exit status code, making the &lt;i&gt;if-then&lt;/i&gt; statement behave in much the same way that &lt;i&gt;if-then&lt;/i&gt; statements work in other programming languages. If the condition is false, the test command exits with a 1, which causes the &lt;i&gt;if-then&lt;/i&gt; statement to fail.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; *) &lt;b&gt;Numeric Comparisons&lt;/b&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Comparison&lt;/td&gt;&lt;td&gt;Description&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;n1 -eq n2&lt;/td&gt;&lt;td&gt;Check if n1 is equal to n2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;n1 -ge n2&lt;/td&gt;&lt;td&gt;Check if n1 is greater than or equal to n2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;n1 -gt n2&lt;/td&gt;&lt;td&gt;Check if n1 is greater than n2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;n1 -le n2&lt;/td&gt;&lt;td&gt;Check if n1 is less than or equal to n2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;n1 -lt n2&lt;/td&gt;&lt;td&gt;Check if n1 is less than n2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;n1 -ne n2&lt;/td&gt;&lt;td&gt;Check if n1 is not equal to n2.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;val1=10&lt;br /&gt;val2=11&lt;br /&gt;if [ $val1 -gt $val2 ]; then&lt;br /&gt;    echo "$val1 is greater than $val2"&lt;br /&gt;else&lt;br /&gt;    echo "$val1 is less than $val2"&lt;br /&gt;fi&lt;br /&gt;if (( $val1 &amp;gt; $val2 )); then&lt;br /&gt;    echo "$val1 is greater than $val2"&lt;br /&gt;else&lt;br /&gt;    echo "$val1 is less than $val2"&lt;br /&gt;fi&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; However, The &lt;code&gt;test&lt;/code&gt; command wasn't able to handle the floating-point value.&lt;br /&gt;&amp;nbsp; &amp;nbsp; You may also notice usage of double parentheses. It provide advanced mathematical formulas for comparisons, no escape is needed in it:&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Symbol&lt;/td&gt;&lt;td&gt;Description&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;val++&lt;/td&gt;&lt;td&gt;Post-increment&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;val--&lt;/td&gt;&lt;td&gt;Post-decrement&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;++val&lt;/td&gt;&lt;td&gt;Pre-increment&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;--val&lt;/td&gt;&lt;td&gt;Pre-decrement&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;!&lt;/td&gt;&lt;td&gt;Logical negation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;∼&lt;/td&gt;&lt;td&gt;Bitwise negation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;**&lt;/td&gt;&lt;td&gt;Exponentiation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;lt;&amp;lt;&lt;/td&gt;&lt;td&gt;Left bitwise shift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;gt;&amp;gt;&lt;/td&gt;&lt;td&gt;Right bitwise shift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;amp;&lt;/td&gt;&lt;td&gt;Bitwise Boolean AND&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;|&lt;/td&gt;&lt;td&gt;Bitwise Boolean OR&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;**&lt;/td&gt;&lt;td&gt;Exponentiation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;amp;&amp;amp;&lt;/td&gt;&lt;td&gt;&amp;amp;&amp;amp; Logical AND&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;||&lt;/td&gt;&lt;td&gt;Logical OR&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; *) &lt;b&gt;String Comparisons&lt;/b&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Comparison&lt;/td&gt;&lt;td&gt;Description&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;str1 = str2&lt;/td&gt;&lt;td&gt;Check if str1 is the same as string str2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;str1 != str2&lt;/td&gt;&lt;td&gt;Check if str1 is not the same as str2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;str1 &amp;lt; str2&lt;/td&gt;&lt;td&gt;Check if str1 is less than str2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;str1 &amp;gt; str2&lt;/td&gt;&lt;td&gt;Check if str1 is greater than str2.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-n str1&lt;/td&gt;&lt;td&gt;Check if str1 has a length greater than zero.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-z str1&lt;/td&gt;&lt;td&gt;Check if str1 has a length of zero.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Trying to determine if one string is less than or greater than another is where things start getting tricky. There are two problems that often plague shell programmers when trying to use the greater-than or less-than features of the test command:&lt;br /&gt;&amp;nbsp; - The greater-than and less-than symbols must be escaped, or the shell will use them as redirection symbols, with the string values as filenames.&lt;br /&gt;&amp;nbsp; - The greater-than and less-than order is not the same as that used with the sort command.  &lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;val1=ben&lt;br /&gt;val2=mike&lt;br /&gt;if [ $val1 \&amp;gt; $val2 ]; then&lt;br /&gt;    echo "$val1 is greater than $val2"&lt;br /&gt;else&lt;br /&gt;    echo "$val1 is less than $val2"&lt;br /&gt;fi&lt;br /&gt;if [[ $val1 &amp;gt; $val2 ]]; then&lt;br /&gt;    echo "$val1 is greater than $val2"&lt;br /&gt;else&lt;br /&gt;    echo "$val1 is less than $val2"&lt;br /&gt;fi&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The double bracketed expression uses the standard string comparison used in the &lt;code&gt;test&lt;/code&gt; command. However, it provides an additional feature that the test command doesn't, &lt;b&gt;pattern matching&lt;/b&gt;. No escape is needed anymore.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Capitalized letters are treated as less than lowercase letters in the &lt;code&gt;test&lt;/code&gt; command. However, when you put the same strings in a file and use the &lt;code&gt;sort&lt;/code&gt; command, the lowercase letters appear first. This is due to the ordering technique each command uses. The &lt;code&gt;test&lt;/code&gt; command uses standard ASCII ordering, using each character's ASCII numeric value to determine the sort order. The &lt;code&gt;sort&lt;/code&gt; command uses the sorting order defined for the system locale language settings. For the English language, the locale settings specify that lowercase letters appear before uppercase letters in sorted order.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; While the &lt;a href="http://mywiki.wooledge.org/BashFAQ/031"&gt;BashFAQ&lt;/a&gt; said: As of bash 4.1, string comparisons using &lt;code&gt;&amp;lt;&lt;/code&gt; or &lt;code&gt;&amp;gt;&lt;/code&gt; respect the current locale when done in &lt;code&gt;[[&lt;/code&gt;, but &lt;b&gt;not&lt;/b&gt; in &lt;code&gt;[&lt;/code&gt; or &lt;code&gt;test&lt;/code&gt;.  In fact, &lt;code&gt;[&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; have &lt;i&gt;never&lt;/i&gt; used locale collating order even though past man pages &lt;i&gt;said&lt;/i&gt; they did.  Bash versions prior to 4.1 do not use locale collating order for &lt;code&gt;[[&lt;/code&gt; either. So you get opposite result when running on CentOS-5.7(bash-3.2) and Ubuntu-10.04(bash-4.1) with &lt;code&gt;[[&lt;/code&gt; operator. And bash-4.1 is consistent with &lt;code&gt;sort&lt;/code&gt; command now.&lt;br /&gt;c) &lt;b&gt;case&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Well, this is easy, just walk through the snippet:&lt;br /&gt;&lt;pre class="brush: bash"&gt;#!/bin/bash&lt;br /&gt;case $USER in&lt;br /&gt;gonwan | barbara)&lt;br /&gt;    echo "Welcome, $USER"&lt;br /&gt;    echo "Please enjoy your visit"&lt;br /&gt;    ;;&lt;br /&gt;testing)&lt;br /&gt;    echo "Special testing account"&lt;br /&gt;    ;;&lt;br /&gt;jessica)&lt;br /&gt;    echo "Do not forget to log off when you're done"&lt;br /&gt;    ;;&lt;br /&gt;*)&lt;br /&gt;    echo "Sorry, you are not allowed here"&lt;br /&gt;    ;;&lt;br /&gt;esac&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All sample code are tested under CentOS-5.7 and Ubuntu-10.04.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5504896508839934731?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5504896508839934731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5504896508839934731&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5504896508839934731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5504896508839934731'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/10/learning-bash-scripts-2.html' title='Learning Bash Scripts (2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1099232198354903941</id><published>2011-10-03T20:30:00.002+08:00</published><updated>2011-10-04T17:18:23.919+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='SSH'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>X11 Forwarding over SSH</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; First, you should install a SSH server:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# centos 5.7&lt;br /&gt;# yum install openssh-server&lt;br /&gt;# ubuntu 10.04&lt;br /&gt;# sudo apt-get install openssh-server&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The configure files are located in &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;. The default ones are OK.&lt;br /&gt;&amp;nbsp; &amp;nbsp; Now connect your server by command below. The -X flag enables X11 forwarding, through which a user can access the local X11 display:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# ssh -X &amp;lt;user&amp;gt;@&amp;lt;address&amp;gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I use Ubuntu as host, and CentOS as guest in VirtualBox. The default &lt;i&gt;NAT&lt;/i&gt; network mode does not allow you to access a guest from host. I just change the network mode to &lt;i&gt;Host-only Network&lt;/i&gt;, and the problem is solved.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Here gives a screenshot: ubuntu-tweak is running on CentOS:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/gonwan1985/6207527608/"&gt;&lt;img alt="ssh_x11forwarding" height="281" src="http://farm7.static.flickr.com/6158/6207527608_e49949fdf2.jpg" width="500" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1099232198354903941?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1099232198354903941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1099232198354903941&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1099232198354903941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1099232198354903941'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/10/x11-forwarding-over-ssh.html' title='X11 Forwarding over SSH'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm7.static.flickr.com/6158/6207527608_e49949fdf2_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2528944186072408786</id><published>2011-09-13T02:13:00.000+08:00</published><updated>2011-09-14T23:49:24.623+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='CIM'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Using CIMPLE with OpenPegasus CIM Server</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; This post just walk through the usage of &lt;a href="http://simplewbem.org/"&gt;CIMPLE&lt;/a&gt; and &lt;a href="http://www.openpegasus.org/"&gt;OpenPegasus&lt;/a&gt; in CentOS 5.x. For background knowledge, please refer to wikipedia.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In CentOS 5.x, just install OpenPegasus(2.9.1) from yum:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# yum install tog-pegasus tog-pegasus-devel&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; We install the devel package since CIMPLE needs to build against it. I used CIMPLE 1.2.4. Before build it, we should fix broken symbolic links of OpenPegasus package, otherwise link error occurs:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# ln -s /usr/lib/libpegconfig.so.1 /usr/lib/libpegconfig.so&lt;br /&gt;# ln -s /usr/lib/libpeglistener.so.1 /usr/lib/libpeglistener.so&lt;br /&gt;# ln -s /usr/lib/libpegprm.so.1 /usr/lib/libpegprm.so&lt;br /&gt;# ln -s /usr/lib/libpegprovidermanager.so.1 /usr/lib/libpegprovidermanager.so&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; There's also a trivial bug which prevent CIMPLE from generating CMPI version of makefiles. Edit &lt;i&gt;${CIMPLE}/src/tools/genmak/main.cpp&lt;/i&gt;, find line "case 'c'", and change to "case 'C'". Now configure and make:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# ./configure --prefix=/usr --with-pegasus=/usr --with-cmpi=/usr/include/Pegasus/Provider/CMPI&lt;br /&gt;# make&lt;br /&gt;# make install&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Aha!! Another annoying bug: wrong permissions in *.tar.gz source package. Fix with:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# chmod 644 /usr/share/cimple/mak/*.mak&lt;br /&gt;# chmod 755 /usr/share/cimple/mak/*.sh&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Demo code refers to CIMPLE official tutorial. It can be found in source package. A repository.mof file is created first:&lt;br /&gt;&lt;pre class="brush: plain"&gt;class President&lt;br /&gt;{&lt;br /&gt;    [Key] uint32 Number;&lt;br /&gt;    string First;&lt;br /&gt;    string Last;&lt;br /&gt;};&lt;br /&gt;class VicePresident&lt;br /&gt;{&lt;br /&gt;    [Key] uint32 Number;&lt;br /&gt;    string First;&lt;br /&gt;    string Last;&lt;br /&gt;};&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Run &lt;i&gt;genproj&lt;/i&gt; to generate class files, provider files, and module files:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# genproj President President VicePresident&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Generate makefiles using &lt;i&gt;genmak&lt;/i&gt;. First line is for OpenPegasus adapter, while second line for CMPI adapter:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# genmak President *.cpp&lt;br /&gt;# genmak -C President *.cpp&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; We implemented &lt;code&gt;President::get_instance()&lt;/code&gt; and &lt;code&gt;President::enum_instance()&lt;/code&gt; in our code:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;Get_Instance_Status President_Provider::get_instance(&lt;br /&gt;    const President* model,&lt;br /&gt;    President*&amp;amp; instance)&lt;br /&gt;{&lt;br /&gt;    /* return GET_INSTANCE_UNSUPPORTED;  */&lt;br /&gt;&lt;br /&gt;    if (model-&amp;gt;Number.value == 1)&lt;br /&gt;    {&lt;br /&gt;        instance = President::create(true);&lt;br /&gt;        instance-&amp;gt;Number.set(1);&lt;br /&gt;        instance-&amp;gt;First.set("George");&lt;br /&gt;        instance-&amp;gt;Last.set("Washington");&lt;br /&gt;        return GET_INSTANCE_OK;&lt;br /&gt;    }&lt;br /&gt;    else if (model-&amp;gt;Number.value == 2)&lt;br /&gt;    {&lt;br /&gt;        instance = President::create(true);&lt;br /&gt;        instance-&amp;gt;Number.set(2);&lt;br /&gt;        instance-&amp;gt;First.set("John");&lt;br /&gt;        instance-&amp;gt;Last.set("Adams");&lt;br /&gt;        return GET_INSTANCE_OK;&lt;br /&gt;    }&lt;br /&gt;    else if (model-&amp;gt;Number.value == 3)&lt;br /&gt;    {&lt;br /&gt;        instance = President::create(true);&lt;br /&gt;        instance-&amp;gt;Number.set(3);&lt;br /&gt;        instance-&amp;gt;First.set("Thomas");&lt;br /&gt;        instance-&amp;gt;Last.set("Jefferson");&lt;br /&gt;        return GET_INSTANCE_OK;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return GET_INSTANCE_NOT_FOUND;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Enum_Instances_Status President_Provider::enum_instances(&lt;br /&gt;    const President* model,&lt;br /&gt;    Enum_Instances_Handler&amp;lt;President&amp;gt;* handler)&lt;br /&gt;{&lt;br /&gt;    President* instance;&lt;br /&gt;&lt;br /&gt;    instance = President::create(true);&lt;br /&gt;    instance-&amp;gt;Number.set(1);&lt;br /&gt;    instance-&amp;gt;First.set("George");&lt;br /&gt;    instance-&amp;gt;Last.set("Washington");&lt;br /&gt;    handler-&amp;gt;handle(instance);&lt;br /&gt;&lt;br /&gt;    instance = President::create(true);&lt;br /&gt;    instance-&amp;gt;Number.set(2);&lt;br /&gt;    instance-&amp;gt;First.set("John");&lt;br /&gt;    instance-&amp;gt;Last.set("Adams");&lt;br /&gt;    handler-&amp;gt;handle(instance);&lt;br /&gt;&lt;br /&gt;    instance = President::create(true);&lt;br /&gt;    instance-&amp;gt;Number.set(3);&lt;br /&gt;    instance-&amp;gt;First.set("Thomas");&lt;br /&gt;    instance-&amp;gt;Last.set("Jefferson");&lt;br /&gt;    handler-&amp;gt;handle(instance);&lt;br /&gt;    &lt;br /&gt;    return ENUM_INSTANCES_OK;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If &lt;code&gt;get_instance()&lt;/code&gt; returns &lt;code&gt;GET_INSTANCE_UNSUPPORTED&lt;/code&gt;, the adapter satisﬁes the request by calling &lt;code&gt;enum_instances()&lt;/code&gt; and searching for a matching instances. It is recommend to leave &lt;code&gt;get_instance()&lt;/code&gt; unsupported when the total number of instances is small.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; After making your module, a registration is required for OpenPegasus CIM server. Start your server and register. The shared library should also be copied to OpenPegasus's providers folder manually:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# cp libPresident.so /usr/lib/Pegasus/providers&lt;br /&gt;# /etc/init.d/tog-pegasus start&lt;br /&gt;# regmod -c ./libPresident.so&lt;br /&gt;Using Pegasus C++ provider interface&lt;br /&gt;Creating class VicePresident (root/cimv2)&lt;br /&gt;Creating class President (root/cimv2)&lt;br /&gt;Registering VicePresident_Provider (class VicePresident)&lt;br /&gt;Registering President_Provider (class President)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; To unregister this provider, run:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# regmod -u -c ./libPresident.so&lt;br /&gt;Using Pegasus C++ provider interface&lt;br /&gt;Unregistering VicePresident_Provider (class VicePresident)&lt;br /&gt;Deleted class VicePresident&lt;br /&gt;Unregistering President_Provider (class President)&lt;br /&gt;Deleted class President&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You may want to dump MOF registration instance for your provide:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# regmod -d ./libPresident.so&lt;br /&gt;instance of PG_ProviderModule&lt;br /&gt;{&lt;br /&gt;    Name = "President_Module";&lt;br /&gt;    Vendor = "Pegasus";&lt;br /&gt;    Version = "2.5.0";&lt;br /&gt;    InterfaceType = "C++Default";&lt;br /&gt;    InterfaceVersion = "2.5.0";&lt;br /&gt;    Location = "President";&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;instance of PG_Provider&lt;br /&gt;{&lt;br /&gt;    Name = "VicePresident_Provider";&lt;br /&gt;    ProviderModuleName = "President_Module";&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;instance of PG_ProviderCapabilities&lt;br /&gt;{&lt;br /&gt;    CapabilityID = "VicePresident";&lt;br /&gt;    ProviderModuleName = "President_Module";&lt;br /&gt;    ProviderName = "VicePresident_Provider";&lt;br /&gt;    ClassName = "VicePresident";&lt;br /&gt;    Namespaces = {"root/cimv2"};&lt;br /&gt;    ProviderType = {2};&lt;br /&gt;    supportedProperties = NULL;&lt;br /&gt;    supportedMethods = NULL;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;instance of PG_Provider&lt;br /&gt;{&lt;br /&gt;    Name = "President_Provider";&lt;br /&gt;    ProviderModuleName = "President_Module";&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;instance of PG_ProviderCapabilities&lt;br /&gt;{&lt;br /&gt;    CapabilityID = "President";&lt;br /&gt;    ProviderModuleName = "President_Module";&lt;br /&gt;    ProviderName = "President_Provider";&lt;br /&gt;    ClassName = "President";&lt;br /&gt;    Namespaces = {"root/cimv2"};&lt;br /&gt;    ProviderType = {2};&lt;br /&gt;    supportedProperties = NULL;&lt;br /&gt;    supportedMethods = NULL;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Install command line utilities and test OpenPegasus server:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# yum install sblim-wbemcli&lt;br /&gt;# yum install sblim-cmpi-base&lt;br /&gt;# wbemcli ecn https://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@localhost:5989/root/cimv2&lt;br /&gt;# wbemcli -nl ei https://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@localhost:5989/root/cimv2:Linux_Processor&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Test our President provider:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# wbemcli ei https://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@localhost:5989/root/cimv2:President&lt;br /&gt;localhost:5989/root/cimv2:President.Number=1 Number=1,First="George",Last="Washington"&lt;br /&gt;localhost:5989/root/cimv2:President.Number=2 Number=2,First="John",Last="Adams"&lt;br /&gt;localhost:5989/root/cimv2:President.Number=3 Number=3,First="Thomas",Last="Jefferson"&lt;br /&gt;# wbemcli gi https://&amp;lt;user&amp;gt;:&amp;lt;pass&amp;gt;@localhost:5989/root/cimv2:President.Number=1&lt;br /&gt;localhost:5989/root/cimv2:President.Number="1" Number=1,First="George",Last="Washington"&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All code can be found in my skydrive here:&lt;br /&gt;&lt;iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="https://skydrive.live.com/embedicon.aspx/share/dev/cmpi.tar.gz?cid=481cbe104492a3af&amp;amp;sc=documents" style="background-color: #fcfcfc; height: 115px; padding: 0pt; width: 98px;" title="Preview"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2528944186072408786?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2528944186072408786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2528944186072408786&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2528944186072408786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2528944186072408786'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/09/using-cimple-with-openpegasus-cim.html' title='Using CIMPLE with OpenPegasus CIM Server'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-4493100799094900570</id><published>2011-08-28T18:17:00.003+08:00</published><updated>2011-08-28T18:41:21.099+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='Shell'/><category scheme='http://www.blogger.com/atom/ns#' term='Bash'/><title type='text'>Learning Bash Scripts (1)</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; In this first post of the series, some basic concepts are introduced. All information from &lt;a href="http://www.amazon.com/Linux-Command-Shell-Scripting-Second/dp/1118004426"&gt;&lt;i&gt;Linux Command Line and Shell Scripting Bible, Second Edition&lt;/i&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;1. &lt;b&gt;Shell Types&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; There are three ways of starting a bash shell:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - As a default login shell at login time&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - As an interactive shell that is not the login shell&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - As a non-interactive shell to run a script&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; a) &lt;b&gt;Login Shell&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; When you log in to the Linux system, the bash shell starts as a login shell. The login shell looks for four different startup files to process commands from. The following is the order in which the bash shell processes the files:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - &lt;i&gt;/etc/profile&lt;/i&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - &lt;i&gt;$HOME/.bash_profile&lt;/i&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - &lt;i&gt;$HOME/.bash_login&lt;/i&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - &lt;i&gt;$HOME/.profile&lt;/i&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; b) &lt;b&gt;Interactive Shell&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If you start a bash shell without logging into a system (such as if you just type bash at a CLI prompt), you start what's called an interactive shell. The interactive shell doesn't act like the login shell, but it still provides a CLI prompt for you to enter commands.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If bash is started as an interactive shell, it doesn't process the &lt;i&gt;/etc/profile&lt;/i&gt; file. Instead, it checks for the &lt;i&gt;.bashrc&lt;/i&gt; file in the user's HOME directory.&lt;br /&gt;&amp;nbsp; &amp;nbsp; c) &lt;b&gt;Non-interactive Shell&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Finally, the last type of shell is a non-interactive shell. This is the shell that the system starts to execute a shell script. This is different in that there isn't a CLI prompt to worry about. However, there may still be specific startup commands you want to run each time you start a script on your system.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; To accommodate that situation, the bash shell provides the BASH_ENV environment variable. When the shell starts a non-interactive shell process, it checks this environment variable for the name of a startup file to execute. If one is present, the shell executes the commands in the file.&lt;br /&gt;&lt;br /&gt;2. &lt;b&gt;Terminfo Database&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The terminfo database is a set of files that identify the characteristics of various terminals that can be used on the Linux system. The Linux system stores the terminfo data for each terminal type as a separate file in the terminfo database directory. The location of this directory often varies from distribution to distribution. Some common locations are &lt;i&gt;/usr/share/terminfo&lt;/i&gt;, &lt;i&gt;/etc/terminfo&lt;/i&gt;, and &lt;i&gt;/lib/terminfo&lt;/i&gt;.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Since the terminfo database files are binary, you cannot see the codes within these files. However, you can use the &lt;code&gt;infocmp&lt;/code&gt; command to convert the binary entries into text.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The Linux shell uses the TERM environment variable to define which terminal emulation setting in the terminfo database to use for a specific session. When the TERM environment variable is set to vt100, the shell knows to use the control codes associated with the vt100 terminfo database entry for sending control codes to the terminal emulator.&lt;br /&gt;&lt;br /&gt;3.&amp;nbsp;&lt;b&gt;Virtual Consoles&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; With modern Linux systems, when the Linux system starts it automatically creates several virtual consoles. A virtual console is a terminal session that runs in memory on the Linux system. Instead of having several dumb terminals connected to the PC, most Linux distributions start seven (or sometimes even more) virtual consoles that you can access from the single PC keyboard and monitor.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In most Linux distributions, you can access the virtual consoles using a simple keystroke combination. Usually you must hold down the Ctl+Alt key combination, and then press a function key (F1 through F8) for the virtual console you want to use. Function key F1 produces virtual console 1, key F2 produces virtual console 2, and so on.&lt;br /&gt;&lt;br /&gt;4. &lt;b&gt;Environment Variables&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; There are two types of environment variables in the bash shell:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - Global variables&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; - Local variables&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Global environment variables are visible from the shell session, and from any child processes that the shell spawns. Local variables are only available in shell that creates them. This makes global environment variables useful in applications that spawn child processes that require information from the parent process.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; a) &lt;b&gt;Get&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; To view the global environment variables, use the &lt;code&gt;printenv&lt;/code&gt; command.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; To display the value of an individual environment variable, use the echo command. When referencing an environment variable, you must place a dollar sign($) before the environment variable name.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Unfortunately there isn't a command that displays only local environment variables. The &lt;code&gt;set&lt;/code&gt; command displays all of the environment variables set for a specific process. However, this also includes the global environment variables.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; b) &lt;b&gt;Set&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You can assign either a numeric or a string value to an environment variable by assigning the variable to a value using the equal sign(=). It's extremely important that there are no spaces between the environment variable name, the equal sign, and the value. If you put any spaces in the assignment, the bash shell interprets the value as a separate command.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The method used to create a global environment variable is to create a local environment variable and then &lt;code&gt;export&lt;/code&gt; it to the global environment.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Of course, if you can create a new environment variable, it makes sense that you can also remove an existing environment variable. You can do this with the &lt;code&gt;unset&lt;/code&gt; command.When referencing the environment variable in the &lt;code&gt;unset&lt;/code&gt; command, remember not to use the dollar sign.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: When dealing with global environment variables, things get a little tricky. If you're in a child process and unset a global environment variable, it applies only to the child process. The global environment variable is still available in the parent process.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-4493100799094900570?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/4493100799094900570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=4493100799094900570&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4493100799094900570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4493100799094900570'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/08/learning-bash-scripts-1.html' title='Learning Bash Scripts (1)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-4289131839046490435</id><published>2011-08-15T01:32:00.004+08:00</published><updated>2011-08-16T00:00:26.521+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Boost'/><category scheme='http://www.blogger.com/atom/ns#' term='C++0x'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Smart Pointers in C++0x and Boost (2)</title><content type='html'>1. &lt;b&gt;Environment&lt;/b&gt;:&lt;br /&gt;*) windows xp&lt;br /&gt;*) gcc-4.4&lt;br /&gt;*) boost-1.43&lt;br /&gt;&lt;br /&gt;2. &lt;b&gt;auto_ptr&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; A smart pointer is an abstract data type that simulates a pointer while providing additional features, such as automatic garbage collection or bounds checking. There's &lt;code&gt;auto_ptr&lt;/code&gt; in C++03 library for general use. But it's not so easy to deal with it. You may encounter pitfalls or limitations. The main drawback of &lt;code&gt;auto_ptr&lt;/code&gt; is that it has the transfer-of-ownership semantic. I just walk through it. Please read comments in code carefully:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;int *test_auto_ptr_exp() {&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; p(new int(1));&lt;br /&gt;    throw runtime_error("auto_ptr test exception.");&lt;br /&gt;    /* exception-safe, p is free even when an exception is thrown. */&lt;br /&gt;    return p.get();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void test_auto_ptr_basic() {&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; p1(new int(1));&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; p2(new int(2));&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; p3(p1);&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; p4;&lt;br /&gt;    p4 = p2;&lt;br /&gt;    if (p1.get()) {  /* NULL */&lt;br /&gt;        cout &amp;lt;&amp;lt; "*p1=" &amp;lt;&amp;lt; *p1 &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;    if (p2.get()) {  /* NULL */&lt;br /&gt;        cout &amp;lt;&amp;lt; "*p2=" &amp;lt;&amp;lt; *p2 &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;    if (p3.get()) {  /* ownership already transferred from p1 to p3 */&lt;br /&gt;        cout &amp;lt;&amp;lt; "*p3=" &amp;lt;&amp;lt; *p3 &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;    if (p4.get()) {  /* ownership already transferred from p2 to p4 */&lt;br /&gt;        cout &amp;lt;&amp;lt; "*p4=" &amp;lt;&amp;lt; *p4 &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;    /* ERROR: void is a type of template specialization */&lt;br /&gt;    //auto_ptr&amp;lt;void&amp;gt; ptr5(new int(3));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void test_auto_ptr_errors() {&lt;br /&gt;    /* ERROR: statically allocated object */&lt;br /&gt;    const char *str = "Hello";&lt;br /&gt;    auto_ptr&amp;lt;const char&amp;gt; p1(str);&lt;br /&gt;    /* ERROR: two auto_ptrs refer to the same object */&lt;br /&gt;    int *pi = new int(5);&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; p2(pi);&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; p3(p2.get());&lt;br /&gt;    p2.~auto_ptr();  /* now p3 is not available too */&lt;br /&gt;    /* ERROR: hold a pointer to a dynamically allocated array */&lt;br /&gt;    /* When destroyed, it only deletes first single object. */&lt;br /&gt;    auto_ptr&amp;lt;int&amp;gt; (new int[10]);&lt;br /&gt;    /* ERROR: store an auto_ptr in a container */&lt;br /&gt;    //vector&amp;lt;auto_ptr&amp;lt;int&amp;gt; &amp;gt; vec;&lt;br /&gt;    //vec.push_back(auto_ptr&amp;lt;int&amp;gt;(new int(1)));&lt;br /&gt;    //vec.push_back(auto_ptr&amp;lt;int&amp;gt;(new int(2)));&lt;br /&gt;    //auto_ptr&amp;lt;int&amp;gt; p4(vec[0]);  /* vec[0] is assigned NULL */&lt;br /&gt;    //auto_ptr&amp;lt;int&amp;gt; p5;&lt;br /&gt;    //p5 = vec[1];  /* vec[1] is assigned NULL */&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;3. &lt;b&gt;unique_ptr&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; To resolve the drawbacks, C++0x deprecates usage of &lt;code&gt;auto_ptr&lt;/code&gt;, and &lt;code&gt;unique_ptr&lt;/code&gt; is the replacement. &lt;code&gt;unique_ptr&lt;/code&gt; makes use of a new C++ langauge feature called &lt;i&gt;rvalue reference&lt;/i&gt; which is similar to our current (left) reference (&lt;i&gt;&amp;amp;&lt;/i&gt;), but spelled (&lt;i&gt;&amp;amp;&amp;amp;&lt;/i&gt;). GCC implemented this feature in 4.3, but &lt;code&gt;unique_ptr&lt;/code&gt; is only available begin from 4.4.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; What is &lt;i&gt;rvalue&lt;/i&gt;?&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;i&gt;rvalues&lt;/i&gt; are temporaries that evaporate at the end of the full-expression in which they live ("at the semicolon"). For example, &lt;i&gt;1729&lt;/i&gt;, &lt;i&gt;x + y&lt;/i&gt;, &lt;i&gt;std::string("meow")&lt;/i&gt;, and &lt;i&gt;x++&lt;/i&gt; are all rvalues.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; While, &lt;i&gt;lvalues&lt;/i&gt; name objects that persist beyond a single expression.  For example, &lt;i&gt;obj&lt;/i&gt;, &lt;i&gt;*ptr&lt;/i&gt;, &lt;i&gt;ptr[index]&lt;/i&gt;, and &lt;i&gt;++x&lt;/i&gt; are all lvalues.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: It's important to remember: &lt;i&gt;lvalueness&lt;/i&gt; versus &lt;i&gt;rvalueness&lt;/i&gt; is a property of expressions, not of objects.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; We may have another whole post to address the &lt;i&gt;rvalue&lt;/i&gt; feature. Now, let's take a look of the basic usage. Please carefully reading the comments:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;unique_ptr&amp;lt;int&amp;gt; get_unique_ptr(int i) {&lt;br /&gt;    return unique_ptr&amp;lt;int&amp;gt; (new int(i));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void use_unique_ptr(unique_ptr&amp;lt;int&amp;gt; p) {&lt;br /&gt;    /* p is deleted when finish running this function. */&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void test_unique_ptr_basic() {&lt;br /&gt;    unique_ptr&amp;lt;int&amp;gt; p(new int(1));&lt;br /&gt;    /*&lt;br /&gt;     * One can make a copy of an rvalue unique_ptr.&lt;br /&gt;     * But one can not make a copy of an lvalue unique_ptr.&lt;br /&gt;     * Note the defaulted and deleted functions usage in source code(c++0x).&lt;br /&gt;     */&lt;br /&gt;    //unique_ptr&amp;lt;int&amp;gt; p2 = p;  /* error */&lt;br /&gt;    //use_unique_ptr(p);       /* error */&lt;br /&gt;    use_unique_ptr(move(p));&lt;br /&gt;    use_unique_ptr(get_unique_ptr(3));&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; One can ONLY make a copy of an rvalue &lt;code&gt;unique_ptr&lt;/code&gt;. This confirms no ownership issues occur like that of &lt;code&gt;auto_ptr&lt;/code&gt;. Since temporary values cannot be referenced after the current expression, it is impossible for two &lt;code&gt;unique_ptr&lt;/code&gt; to refer to a same pointer. You may also noticed the &lt;i&gt;move&lt;/i&gt; function. We will also discuss it in a later post.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Some more snippet:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;struct aclass {&lt;br /&gt;    aclass() { cout &amp;lt;&amp;lt; "in aclass::ctor()" &amp;lt;&amp;lt; endl; }&lt;br /&gt;    ~aclass() { cout &amp;lt;&amp;lt; "in aclass::dtor()" &amp;lt;&amp;lt; endl; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct aclass_deleter {&lt;br /&gt;    void operator()(void *p) {&lt;br /&gt;        delete static_cast&amp;lt;aclass *&amp;gt; (p);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template&amp;lt;class T&amp;gt;&lt;br /&gt;struct array_deleter {&lt;br /&gt;    void operator()(T *array) {&lt;br /&gt;        delete[] array;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;typedef array_deleter&amp;lt;aclass&amp;gt; aclass_array_deleter;&lt;br /&gt;typedef unique_ptr&amp;lt;aclass, aclass_array_deleter&amp;gt; aclass_array_ptr;&lt;br /&gt;&lt;br /&gt;void test_unique_ptr_custom_deleter() {&lt;br /&gt;    /*&lt;br /&gt;     * Hold a pointer to a dynamically allocated array.&lt;br /&gt;     * aaptr &amp;amp; aaptr2 are deleted when finish running this function.&lt;br /&gt;     */&lt;br /&gt;    aclass_array_ptr aaptr(new aclass[3]);&lt;br /&gt;    unique_ptr&amp;lt;aclass[]&amp;gt; aaptr2(new aclass[3]);  /* default_deleter&amp;lt;T[]&amp;gt; */&lt;br /&gt;    /* allow void pointer, but a custom deleter must be used. */&lt;br /&gt;    unique_ptr&amp;lt;void, aclass_deleter&amp;gt; p3(new aclass);&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;unique_ptr&lt;/code&gt; can hold pointers to an array. &lt;code&gt;unique_ptr&lt;/code&gt; defines &lt;i&gt;deleter&lt;/i&gt;s to free memory of its internal pointer. There are pre-defined &lt;code&gt;default_deleter&lt;/code&gt; using &lt;i&gt;delete&lt;/i&gt; and &lt;i&gt;delete[]&lt;/i&gt;(array) for general deallocation. You can also define your customized ones. In addition, a &lt;code&gt;void&lt;/code&gt; type can be used.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: To compile the code, you must specify the &lt;code&gt;-std=c++0x&lt;/code&gt; flag.&lt;br /&gt;&lt;br /&gt;4. &lt;b&gt;shared_ptr&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; A &lt;code&gt;shared_ptr&lt;/code&gt; is used to represent shared ownership; that is, when two pieces of code needs access to some data but neither has exclusive ownership (in the sense of being responsible for destroying the object). A &lt;code&gt;shared_ptr&lt;/code&gt; is a kind of counted pointer where the object pointed to is deleted when the use count goes to zero.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Following snippet shows the use count changes when using &lt;code&gt;shared_ptr&lt;/code&gt;. The use count changes from 0 to 3, then changes back to 0:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;struct bclass {&lt;br /&gt;    int i;&lt;br /&gt;    bclass(int i) { this-&amp;gt;i = i; }&lt;br /&gt;    virtual ~bclass() { cout &amp;lt;&amp;lt; "in bclass::dtor() with i=" &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct cclass: bclass {&lt;br /&gt;    cclass(int i) : bclass(i) { }&lt;br /&gt;    virtual ~cclass() { cout &amp;lt;&amp;lt; "in cclass::dtor() with i=" &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void use_shared_ptr(shared_ptr&amp;lt;int&amp;gt; p) {&lt;br /&gt;    cout &amp;lt;&amp;lt; "count=" &amp;lt;&amp;lt; p.use_count() &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void test_shared_ptr_basic() {&lt;br /&gt;    shared_ptr&amp;lt;int&amp;gt; p;&lt;br /&gt;    cout &amp;lt;&amp;lt; "count=" &amp;lt;&amp;lt; p.use_count() &amp;lt;&amp;lt; endl;&lt;br /&gt;    p.reset(new int(1));&lt;br /&gt;    cout &amp;lt;&amp;lt; "count=" &amp;lt;&amp;lt; p.use_count() &amp;lt;&amp;lt; endl;&lt;br /&gt;    shared_ptr&amp;lt;int&amp;gt; p2 = p;&lt;br /&gt;    cout &amp;lt;&amp;lt; "count=" &amp;lt;&amp;lt; p.use_count() &amp;lt;&amp;lt; endl;&lt;br /&gt;    use_shared_ptr(p2);&lt;br /&gt;    cout &amp;lt;&amp;lt; "count=" &amp;lt;&amp;lt; p.use_count() &amp;lt;&amp;lt; endl;&lt;br /&gt;    p2.~shared_ptr();&lt;br /&gt;    cout &amp;lt;&amp;lt; "count=" &amp;lt;&amp;lt; p.use_count() &amp;lt;&amp;lt; endl;&lt;br /&gt;    p2.~shared_ptr();&lt;br /&gt;    cout &amp;lt;&amp;lt; "count=" &amp;lt;&amp;lt; p.use_count() &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Snippets showing pointer type conversion:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;void test_shared_ptr_convertion() {&lt;br /&gt;    /* p is deleted accurately without custom deleter */&lt;br /&gt;    shared_ptr&amp;lt;void&amp;gt; p(new aclass);&lt;br /&gt;    /* use parent type to hold child object */&lt;br /&gt;    shared_ptr&amp;lt;bclass&amp;gt; p2(new cclass(10));&lt;br /&gt;    shared_ptr&amp;lt;cclass&amp;gt; p3 = static_pointer_cast&amp;lt;cclass&amp;gt; (p2);&lt;br /&gt;    cout &amp;lt;&amp;lt; "p3-&amp;gt;i=" &amp;lt;&amp;lt; p3-&amp;gt;i &amp;lt;&amp;lt; endl;&lt;br /&gt;    p3-&amp;gt;i = 20;&lt;br /&gt;    cout &amp;lt;&amp;lt; "p2-&amp;gt;i=" &amp;lt;&amp;lt; p2-&amp;gt;i &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The &lt;code&gt;void&lt;/code&gt; type can be used directly without a custom deleter, which is required in &lt;code&gt;unique_ptr&lt;/code&gt;. Actually, &lt;code&gt;shared_ptr&lt;/code&gt; has already save the exact type info in its constructor. Refer to source code for details :). And &lt;code&gt;static_pointer_cast&lt;/code&gt; function is used to convert between pointer types.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Unlike &lt;code&gt;auto_ptr&lt;/code&gt;, Since &lt;code&gt;shared_ptr&lt;/code&gt; can be &lt;i&gt;shared&lt;/i&gt;, it can be used in STL containers:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;typedef shared_ptr&amp;lt;bclass&amp;gt; bclass_ptr;&lt;br /&gt;&lt;br /&gt;struct bclass_ops {&lt;br /&gt;    void operator()(const bclass_ptr&amp;amp; p) {&lt;br /&gt;        cout &amp;lt;&amp;lt; p-&amp;gt;i &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;    bool operator()(const bclass_ptr&amp;amp; a, const bclass_ptr&amp;amp; b) {&lt;br /&gt;        return a-&amp;gt;i &amp;lt; b-&amp;gt;i;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void test_shared_ptr_containers() {&lt;br /&gt;    vector&amp;lt;bclass_ptr&amp;gt; vec1, vec2;&lt;br /&gt;    bclass_ptr ptr(new bclass(1));&lt;br /&gt;    vec1.push_back(ptr);&lt;br /&gt;    vec2.push_back(ptr);&lt;br /&gt;    ptr.reset(new bclass(2));&lt;br /&gt;    vec1.push_back(ptr);&lt;br /&gt;    vec2.push_back(ptr);&lt;br /&gt;    ptr.reset(new bclass(3));&lt;br /&gt;    vec1.push_back(ptr);&lt;br /&gt;    vec2.push_back(ptr);&lt;br /&gt;    for_each(vec1.begin(), vec1.end(), bclass_ops());&lt;br /&gt;    reverse(vec2.begin(), vec2.end());&lt;br /&gt;    for_each(vec2.begin(), vec2.end(), bclass_ops());&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: &lt;code&gt;shared_ptr&lt;/code&gt; is available in both TR1 and Boost library. You can use either of them, for their interfaces are compatible. In addition, there are &lt;a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/shared_ptr.html"&gt;dual C++0x and TR1 implementation&lt;/a&gt;. The TR1 implementation is considered relatively stable, so is unlikely to change unless bug fixes require it.&lt;br /&gt;&lt;br /&gt;5. &lt;b&gt;weak_ptr&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;weak_ptr&lt;/code&gt; objects are used for breaking cycles in data structures. See snippet:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;struct mynode {&lt;br /&gt;    int i;&lt;br /&gt;    shared_ptr&amp;lt;mynode&amp;gt; snext;&lt;br /&gt;    weak_ptr&amp;lt;mynode&amp;gt; wnext;&lt;br /&gt;    mynode(int i) { this-&gt;i = i; }&lt;br /&gt;    ~mynode() { cout &amp;lt;&amp;lt; "in mynode::dtor() with i=" &amp;lt; i &amp;lt; endl; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void test_weak_ptr() {&lt;br /&gt;    shared_ptr&amp;lt;mynode&amp;gt; head(new mynode(1));&lt;br /&gt;    head-&amp;gt;snext = shared_ptr&amp;lt;mynode&amp;gt;(new mynode(2));&lt;br /&gt;    /* use weak_ptr to solve cyclic dependency */&lt;br /&gt;    //head-&amp;gt;snext = head;&lt;br /&gt;    head-&amp;gt;wnext = head;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If we use uncomment to use &lt;code&gt;shared_ptr&lt;/code&gt;, &lt;i&gt;head&lt;/i&gt; is not freed since there still one reference to it when exiting the function. By using &lt;code&gt;weak_ptr&lt;/code&gt;, this code works fine.&lt;br /&gt;&lt;br /&gt;6. &lt;b&gt;scoped_ptr&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;scoped_ptr&lt;/code&gt; template is a simple solution for simple needs. It supplies a basic "resource acquisition is initialization" facility, without shared-ownership or transfer-of-ownership semantics.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; This class is only available in Boost. Since &lt;code&gt;unique_ptr&lt;/code&gt; is already there in C++0x, this class may be thought as redundant. Snippet is also simple:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;void test_scoped_ptr() {&lt;br /&gt;    /* simple solution for simple needs */&lt;br /&gt;    scoped_ptr&amp;lt;aclass&amp;gt; p(new aclass);&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Complete and updated code can be found on google code host &lt;a href="http://code.google.com/p/qskin/source/browse/trunk/study/cpp/smartptr.cpp"&gt;here&lt;/a&gt;. I use conditional compilation to swith usage between TR1 and Boost implementation in code. Hope you find it useful. &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-4289131839046490435?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/4289131839046490435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=4289131839046490435&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4289131839046490435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4289131839046490435'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/08/smart-pointers-in-c0x-and-boost-2.html' title='Smart Pointers in C++0x and Boost (2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5038245606191586584</id><published>2011-08-14T23:29:00.001+08:00</published><updated>2011-08-15T23:36:05.973+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Boost'/><category scheme='http://www.blogger.com/atom/ns#' term='C++0x'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Smart Pointers in C++0x and Boost</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Let clarify some concepts first. What is &lt;b&gt;C++0x&lt;/b&gt;? Wikipedia gives some overview &lt;a href="http://en.wikipedia.org/wiki/C++0x"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: plain"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; C++0x is intended to replace the existing C++ standard, ISO/IEC 14882, which was published in 1998 and updated in 2003. These predecessors are informally but commonly known as C++98 and C++03. The new standard will include several additions to the core language and will extend the C++ standard library, incorporating most of the C++ Technical Report 1 (TR1) libraries — with the exception of the library of mathematical special functions.&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then why it is called C++0x? As &lt;a href="http://www.research.att.com/~bs/homepage.html"&gt;Bjarne Stroustrup&lt;/a&gt; addressed &lt;a href="http://www2.research.att.com/~bs/bs_faq.html#When-next-standard"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: plain"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The aim is for the 'x' in C++0x to become '9': C++09, rather than (say) C++0xA (hexadecimal :-).&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You may also noticed TR1, also refer &lt;a href="http://en.wikipedia.org/wiki/C++_Technical_Report_1"&gt;here&lt;/a&gt; in Wikipedia:&lt;br /&gt;&lt;pre class="brush: plain"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; C++ Technical Report 1 (TR1) is the common name for ISO/IEC TR 19768, C++ Library Extensions, which is a document proposing additions to the C++ standard library. The additions include regular expressions, smart pointers, hash tables, and random number generators. TR1 is not a standard itself, but rather a draft document. However, most of its proposals are likely to become part of the next official standard.&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You got the relationship? C++0x is the standard adding features to both language and standard library. A large set of TR1 libraries and some additional libraries. For instance, &lt;code&gt;unique_ptr&lt;/code&gt; is not defined in TR1, but is included in C++0x.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; As of 12 August 2011, the C++0x specification has been approved by the ISO.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Another notable concept is the &lt;a href="http://www.boost.org/"&gt;Boost&lt;/a&gt; library. It can be regarded as a portable, easy-to-use extension to the current C++03 standard library. And some libraries like smart pointers, regular expressions have already been included in TR1. You can find license headers regarding the donation of the boost code in libstdc++ source files. While in TR2, some more boost code are to be involved.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; TR1 libraries can be accessed using &lt;code&gt;std::tr1&lt;/code&gt; namespace. More info on Wikipedia &lt;a href="http://en.wikipedia.org/wiki/C++0x#C.2B.2B_standard_library_changes"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: plain"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Various full and partial implementations of TR1 are currently available using the namespace std::tr1. For C++0x they will be moved to namespace std. However, as TR1 features are brought into the C++0x standard library, they are upgraded where appropriate with C++0x language features that were not available in the initial TR1 version. Also, they may be enhanced with features that were possible under C++03, but were not part of the original TR1 specification.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The committee intends to create a second technical report (called TR2) after the standardization of C++0x is complete. Library proposals which are not ready in time for C++0x will be put into TR2 or further technical reports.&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The article seems to be a bit too long so far, I decide to give my snippets in a later post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5038245606191586584?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5038245606191586584/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5038245606191586584&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5038245606191586584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5038245606191586584'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/08/smart-pointers-in-c0x-and-boost.html' title='Smart Pointers in C++0x and Boost'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-7607374002617977572</id><published>2011-08-09T01:25:00.001+08:00</published><updated>2011-08-09T01:31:05.075+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='BIOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>Retrieve BIOS Info Programmatically in Linux</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Generally, BIOS info can be found by &lt;b&gt;dmidecode&lt;/b&gt; utility(run as root), like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# dmidecode --type bios&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Here, I retrieve it by using &lt;b&gt;libhd&lt;/b&gt; library provided in &lt;b&gt;hwinfo&lt;/b&gt; utility:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;/* bios.c */&lt;br /&gt;#include &amp;lt;hd.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* install libhd-dev/libhd-devel packages to build */&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    hd_data_t *hddata;&lt;br /&gt;    hd_t *hdlist;&lt;br /&gt;    hd_smbios_t *smbios;&lt;br /&gt;&lt;br /&gt;    if (getuid() != 0) {&lt;br /&gt;        printf("ERROR: Please run as root.\n");&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    hddata = (hd_data_t *)calloc(1, sizeof(hd_data_t));&lt;br /&gt;    hdlist = hd_list(hddata, hw_bios, 1, NULL);&lt;br /&gt;&lt;br /&gt;    for (smbios = hddata-&gt;smbios; smbios; smbios = smbios-&gt;next) {&lt;br /&gt;        if (smbios-&gt;any.type == sm_biosinfo) {&lt;br /&gt;            break;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    if (!smbios) {&lt;br /&gt;        printf("INFO: No BIOS info found.\n");&lt;br /&gt;    } else {&lt;br /&gt;        if (smbios-&gt;biosinfo.vendor) {&lt;br /&gt;            printf("Vendor:       \"%s\"\n", smbios-&gt;biosinfo.vendor);&lt;br /&gt;        }&lt;br /&gt;        if (smbios-&gt;biosinfo.version) {&lt;br /&gt;            printf("Version:      \"%s\"\n", smbios-&gt;biosinfo.version);&lt;br /&gt;        }&lt;br /&gt;        if (smbios-&gt;biosinfo.date) {&lt;br /&gt;            printf("Release Date: \"%s\"\n", smbios-&gt;biosinfo.date);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    hd_free_hd_list(hdlist);&lt;br /&gt;    hd_free_hd_data(hddata);&lt;br /&gt;    free(hddata);&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-7607374002617977572?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/7607374002617977572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=7607374002617977572&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7607374002617977572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7607374002617977572'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/08/retrieve-bios-info-programmatically-in.html' title='Retrieve BIOS Info Programmatically in Linux'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-8627381549551058906</id><published>2011-07-31T04:28:00.007+08:00</published><updated>2011-08-08T00:24:47.558+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CentOS'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>Installing CentOS 5.x with Just the First CD</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Since the DVD size of CentOS 5.x is largely increased(1.7G for 3.x, 2.3G for 4.x, while 4.0G for 5.x), I decided to use the CD approach. I downloaded the first CD image from one of its mirror site: &lt;a href="http://mirrors.163.com/centos/5.6/isos/i386/"&gt;http://mirrors.163.com/centos/5.6/isos/i386/&lt;/a&gt;.&lt;br /&gt;&amp;nbsp; &amp;nbsp; Now, follow the official FAQ &lt;a href="http://wiki.centos.org/FAQ/CentOS5#head-c79c201900d22f163a445f134fcc6c916eb3cb6e"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: plain"&gt;  - You can do a minimal install that just requires the first CD by performing the following two steps during the installation:&lt;br /&gt;    * During the category/task selection, deselect all package categories, and choose the "Customize now" option at the bottom of screen.&lt;br /&gt;    * During the customized package selection, deselect everything ( including the Base group ). &lt;br /&gt;  - There are reports that more than CD 1 is required in the following case:&lt;br /&gt;    * If you use some software raid options (this will also require CD 2 and 5)&lt;br /&gt;    * If you use encrypted filesystems &lt;br /&gt;  - When the anaconda installer notes that additional disks will be required but you desire a one CD install, the quick answer is one or more of the following approaches:&lt;br /&gt;    * Trim back and do a minimal install. Then once the install is up and running, pull in more packages with yum and add more options later. &lt;br /&gt;  - If you want to avoid using more than one CD but want to install more than just the minimal set of packages, you could also consider doing a network installation. A network installation ISO (called boot.iso) is available from the 5/os/&amp;lt;arch&amp;gt;/images/ directory on CentOS mirrors.&lt;br /&gt;  - This latter mode of installation, however, is only really reliable via a LAN (an Intranet installation) and not via the Internet. &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; From my practice, you MUST follow the de-selection order. Otherwise, it will still require other CDs. The actual installation lasts for about 1 minutes(installation of *.rpm files). After reboot, the system gives you a minimum installation with only text mode support. Now login with your root account, and make sure your network is ready. Additional components shall be installed manually using yum:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# yum groupinstall "Base" "X Window System" "GNOME Desktop Environment"&lt;/pre&gt;&amp;nbsp; &amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: All group names are case-sensitive. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Actually, if only "X Window System" are passed to yum, you will get a simple GUI with an xterm and an xclock after running "startx" command.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You may want to take coffee during the process. For me, about 350M contents were downloaded. Reboot when finished and add "single" option to enter single mode in GRUB menu. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Since the first CD does not install GUI contents, so the runlevel is set to 3(text mode) by default after installation. We should switch it to 5(GUI mode) by editing /etc/inittab file, Find the line and change the middle value from 3 to 5.:&lt;br /&gt;&lt;pre class="brush: plain"&gt;id:3:initdefault:&lt;/pre&gt;&amp;nbsp; &amp;nbsp; Now, we want to start the "firstboot" configuration utility to simplify our user account creation and other initial configurations. Check /etc/sysconfig/firstboot file, and make sure the value is set to "YES" like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;RUN_FIRSTBOOT=YES&lt;/pre&gt;&amp;nbsp; &amp;nbsp; If the value is "NO", the "firstboot" utility is skipped and GDM is displayed directly. When all have been done, issue the "exit" command to return to the normal startup process. This time, the "firstboot" wizard should show. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Here is the GDM screenshot after all above steps: &lt;br /&gt;&lt;a href="http://www.flickr.com/photos/gonwan1985/5989997912/" title="centos5_gdm"&gt;&lt;img alt="centos5_gdm" border="0" height="375" src="http://farm7.static.flickr.com/6133/5989997912_02cec9fe6d.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;PS&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In 6.x, CentOS provides LiveCD and LiveDVD that can be used also for installation. But in 5.x, they can only be used for trial experience. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In 4.x/3.x, the openoffice suite is outdated, I suggest to not install them. I also suggest to remove redundant kernels: &lt;br /&gt;&lt;pre class="brush: plain"&gt;# For 4.x&lt;br /&gt;# yum remove kernel-smp kernel-smp-devel kernel-hugemem-devel&lt;br /&gt;# For 3.x&lt;br /&gt;# rpm -e kernel-smp&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; There's 4.9 release but no 4.9 *.iso images. The readme.txt says:&lt;br /&gt;&lt;pre class="brush: plain"&gt;- The upstream provider did not respin media for the 4.9 release and therefore the CentOS project will also not respin our install media. &lt;br /&gt;- Installs moving forward will be off the 4.8 media and an upgrade will move you from version 4.8 to version 4.9. &lt;br /&gt;- We do this to maintain compatibility with 3rd party kernel drivers which are designed to be installed as part of the installation process. &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Run "yum update" to update from 4.8 to 4.9. For me, about 300M contents were downloaded.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In 3.x release, I suggest to select "Kernel Development" group during installation. The 2.4.x kernel needs its source to compile kernel modules(like virtual machine addons).&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-8627381549551058906?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/8627381549551058906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=8627381549551058906&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8627381549551058906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8627381549551058906'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/07/installing-centos-5x-with-just-first-cd.html' title='Installing CentOS 5.x with Just the First CD'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm7.static.flickr.com/6133/5989997912_02cec9fe6d_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-6005309042000171032</id><published>2011-07-26T21:12:00.003+08:00</published><updated>2011-07-26T23:04:25.769+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MP4'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='iPod'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Encoding MP4 Files for iPod on Ubuntu 10.04</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; I used mencoder utility to convert my video files. But it was compiled without libfaac. So if you specify AAC encoding, an error occurs. Details and solutions can be found &lt;a href="http://ubuntuforums.org/showthread.php?t=1117283"&gt;here&lt;/a&gt;. I just added the Medibuntu repository as &lt;a href="https://help.ubuntu.com/community/Medibuntu"&gt;described&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo wget --output-document=/etc/apt/sources.list.d/medibuntu.list http://www.medibuntu.org/sources.list.d/$(lsb_release -cs).list&lt;br /&gt;# sudo apt-get --quiet update&lt;br /&gt;# sudo apt-get --yes --quiet --allow-unauthenticated install medibuntu-keyring&lt;br /&gt;# sudo apt-get --quiet update&lt;/pre&gt;&amp;nbsp; &amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: ffmpeg utility in Lucid release does not support *.rm/*.rmvb yet.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then install mencoder and codecs:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install mencoder libavcodec-extra-52 libavformat-extra-52&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now you can convert videos. Here's a sample to convert a *.rmvb(848x480) to a *.mp4(320x240):&lt;br /&gt;&lt;pre class="brush: plain"&gt;# mencoder -oac lavc -ovc lavc -lavcopts acodec=libfaac:abitrate=96:aglobal=1:vcodec=mpeg4:vbitrate=500:vglobal=1 -vf scale=320:180,harddup -vf-add expand=:240 -ofps 24000/1001 -of lavf source.rmvb -o target.mp4&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Modify fps/codec/bitrate values as you wish. The aglobal &amp;amp; vglobal options seem to be essential for iPod.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In order to keep video aspect after scaling, the output file should be 360x204.we use the -vf-add filter to add black band to the top and bottom of it. Othercommand line options, please refer to its manpage.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Lastly, install gtkpod to import your *.mp4 files.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-6005309042000171032?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/6005309042000171032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=6005309042000171032&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6005309042000171032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6005309042000171032'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/07/encoding-mp4-files-for-ipod-on-ubuntu.html' title='Encoding MP4 Files for iPod on Ubuntu 10.04'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5440727566495521739</id><published>2011-05-31T01:15:00.002+08:00</published><updated>2011-08-09T01:31:34.009+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Vim'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>File Encodings in Vim</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; By default, You need to guide Vim to decode double-byte encodings like GBK and Big5. The default Vim configuration only works well with Unicode encodings including utf-8, utf-16, utf-16be etc..Edit your .vimrc file, add line like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;set fileencodings=ucs-bom,utf-8,gbk,big5,latin1&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now Vim is able to detect and decode GBK and Big5 encodings automatically. And according my experience, Vim respects utf-16 and utf-16be files only they have BOM byes. Otherwise, these files are wrongly decoded. In this case, you may want to manually reopen the file using a correct encoding. The Vim command like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:e ++enc=&amp;lt;your_encoding&amp;gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; And Vim does not store BOM when saving by default. To enable/disable BOM saving, use:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:set bomb&lt;br /&gt;:set nobomb&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I've attached a series of text files to learn the usage. These text file all contains string "123你好", but saved in different encodings. Let's list their code points first:&lt;br /&gt;&lt;table&gt;&lt;tbody align="center"&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;你&lt;/td&gt;&lt;td&gt;好&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GBK&lt;/td&gt;&lt;td&gt;0x31&lt;/td&gt;&lt;td&gt;0x32&lt;/td&gt;&lt;td&gt;0x33&lt;/td&gt;&lt;td&gt;0xc4e3&lt;/td&gt;&lt;td&gt;0xbac3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Big5&lt;/td&gt;&lt;td&gt;0x31&lt;/td&gt;&lt;td&gt;0x32&lt;/td&gt;&lt;td&gt;0x33&lt;/td&gt;&lt;td&gt;0xa741&lt;/td&gt;&lt;td&gt;0xa66e&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Unicode&lt;/td&gt;&lt;td&gt;0x31&lt;/td&gt;&lt;td&gt;0x32&lt;/td&gt;&lt;td&gt;0x33&lt;/td&gt;&lt;td&gt;0x4f60&lt;/td&gt;&lt;td&gt;0x597d&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UTF-8 encoded&lt;/td&gt;&lt;td&gt;0x31&lt;/td&gt;&lt;td&gt;0x32&lt;/td&gt;&lt;td&gt;0x33&lt;/td&gt;&lt;td&gt;0xe4bda0&lt;/td&gt;&lt;td&gt;0xe5a5bd&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; And our hexdump's here, note the byte order:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# hexdump -C test_gbk.txt&lt;br /&gt;00000000  31 32 33 c4 e3 ba c3                              |123....|&lt;br /&gt;00000007&lt;br /&gt;# hexdump -C test_big5.txt&lt;br /&gt;00000000  31 32 33 a7 41 a6 6e                              |123.A.n|&lt;br /&gt;00000007&lt;br /&gt;# hexdump -C test_ucs2be.txt&lt;br /&gt;00000000  00 31 00 32 00 33 4f 60  59 7d                    |.1.2.3O`Y}|&lt;br /&gt;0000000a&lt;br /&gt;# hexdump -C test_ucs2be_bom.txt&lt;br /&gt;00000000  fe ff 00 31 00 32 00 33  4f 60 59 7d              |...1.2.3O`Y}|&lt;br /&gt;0000000c&lt;br /&gt;# hexdump -C test_ucs2le.txt&lt;br /&gt;00000000  31 00 32 00 33 00 60 4f  7d 59                    |1.2.3.`O}Y|&lt;br /&gt;0000000a&lt;br /&gt;# hexdump -C test_ucs2le_bom.txt&lt;br /&gt;00000000  ff fe 31 00 32 00 33 00  60 4f 7d 59              |..1.2.3.`O}Y|&lt;br /&gt;0000000c&lt;br /&gt;# hexdump -C test_utf8.txt&lt;br /&gt;00000000  31 32 33 e4 bd a0 e5 a5  bd                       |123......|&lt;br /&gt;00000009&lt;br /&gt;# hexdump -C test_utf8_bom.txt&lt;br /&gt;00000000  ef bb bf 31 32 33 e4 bd  a0 e5 a5 bd              |...123......|&lt;br /&gt;0000000c&lt;br /&gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; My test text files are &lt;a href="http://cid-481cbe104492a3af.office.live.com/self.aspx/share/dev/encodings.tar.gz"&gt;here&lt;/a&gt;. More info:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help encoding&lt;br /&gt;:help fileencoding&lt;br /&gt;:help fileencodings&lt;br /&gt;:help encoding-names&lt;br /&gt;:help bomb&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5440727566495521739?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5440727566495521739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5440727566495521739&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5440727566495521739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5440727566495521739'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/05/file-encodings-in-vim.html' title='File Encodings in Vim'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3571038557924475058</id><published>2011-05-23T01:11:00.007+08:00</published><updated>2011-08-09T01:32:00.398+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Vim'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Vim Tips in Ubuntu 10.04</title><content type='html'>&amp;nbsp; &amp;nbsp; The objective of this article is to make Vim your programmer's editor.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; First, a normal version of Vim should be installed to enable syntax highlighting. The default installation of Ubuntu 10.04 only contains a compact version "vim-tiny":&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install vim&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then copy a local vim configure file:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# cp /etc/vim/vimrc ~/.vimrc&lt;br /&gt;# vi ~/.vimrc&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;1. Line Number:&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Add line into the .vimrc file:&lt;br /&gt;&lt;pre class="brush: plain"&gt;set number&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; A similar command can be used to show/hide line number when editing on the fly:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:set number&lt;br /&gt;:set nonumber&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Related help:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help set&lt;br /&gt;:help 'number'&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;2. Tab-space Conversion&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; From the Vim help:&lt;br /&gt;&lt;pre class="brush: plain"&gt;'tabstop' 'ts'          number  (default 8)&lt;br /&gt;                        local to buffer&lt;br /&gt;        Number of spaces that a &amp;lt;Tab&amp;gt; in the file counts for.  Also see&lt;br /&gt;        |:retab| command, and 'softtabstop' option.&lt;br /&gt;&lt;br /&gt;        Note: Setting 'tabstop' to any other value than 8 can make your file&lt;br /&gt;        appear wrong in many places (e.g., when printing it).&lt;br /&gt;&lt;br /&gt;        There are four main ways to use tabs in Vim:&lt;br /&gt;        1. Always keep 'tabstop' at 8, set 'softtabstop' and 'shiftwidth' to 4&lt;br /&gt;           (or 3 or whatever you prefer) and use 'noexpandtab'.  Then Vim&lt;br /&gt;           will use a mix of tabs and spaces, but typing &amp;lt;Tab&amp;gt; and &amp;lt;BS&amp;gt; will&lt;br /&gt;           behave like a tab appears every 4 (or 3) characters.&lt;br /&gt;        2. Set 'tabstop' and 'shiftwidth' to whatever you prefer and use&lt;br /&gt;           'expandtab'.  This way you will always insert spaces.  The&lt;br /&gt;           formatting will never be messed up when 'tabstop' is changed.&lt;br /&gt;        3. Set 'tabstop' and 'shiftwidth' to whatever you prefer and use a&lt;br /&gt;           |modeline| to set these values when editing the file again.  Only&lt;br /&gt;           works when using Vim to edit the file.&lt;br /&gt;        4. Always set 'tabstop' and 'shiftwidth' to the same value, and&lt;br /&gt;           'noexpandtab'.  This should then work (for initial indents only)&lt;br /&gt;           for any tabstop setting that people use.  It might be nice to have&lt;br /&gt;           tabs after the first non-blank inserted as spaces if you do this&lt;br /&gt;           though.  Otherwise aligned comments will be wrong when 'tabstop' is&lt;br /&gt;           changed.&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I will choose to use the 2nd approach, so add:&lt;br /&gt;&lt;pre class="brush: plain"&gt;set expandtab&lt;br /&gt;set tabstop=4&lt;br /&gt;set shiftwidth=4&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The auto-indent feature is also useful:&lt;br /&gt;&lt;pre class="brush: plain"&gt;set autoindent&lt;/pre&gt;&amp;nbsp; &amp;nbsp; When setting expandtab, a real tab can be input by &amp;lt;Ctrl-v&amp;gt;_&amp;lt;Tab&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Related help:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help autoindent&lt;br /&gt;:help expandtab&lt;br /&gt;:help tabstop&lt;br /&gt;:help shiftwidth&lt;br /&gt;:help retab&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;3. Option 'modeline':&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If you start editing a new file, and the 'modeline' option is on, a number of lines at the beginning and end of the file are checked for modelines. This is simply enabled by adding:&lt;br /&gt;&lt;pre class="brush: plain"&gt;set modeline&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Your C/C++ comment may look like one of the following:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;/* vi: set ai ts=4 sw=4: */&lt;br /&gt;/* vim: set ai et ts=4 sw=4: */&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; And likely, the Python comments:&lt;br /&gt;&lt;pre class="brush: python"&gt;# vi: set ai ts=4 sw=4:&lt;br /&gt;# vim: set ai et ts=4 sw=4:&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Here, &lt;code&gt;ai&lt;/code&gt;, &lt;code&gt;et&lt;/code&gt;, &lt;code&gt;ts&lt;/code&gt; and &lt;code&gt;sw&lt;/code&gt; are just abbreviations. And &lt;code&gt;expandtab&lt;/code&gt; is an option only in Vim, not Vi.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Read related help by typing:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help modeline&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;4. Using Taglist:&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; There are lots of useful scripts in the Vim website that we can use. But Actually, Ubuntu repository also has some of them included:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install vim-scripts vim-addon-manager&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; After installation, these scripts are just downloaded, but not installed for your Vim. We list available script by typing:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# vim-addons&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Output on Lucid 10.04:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# Name                     User Status  System Status &lt;br /&gt;align                       removed       removed       &lt;br /&gt;alternate                   removed       removed       &lt;br /&gt;bufexplorer                 removed       removed       &lt;br /&gt;calendar                    removed       removed       &lt;br /&gt;closetag                    removed       removed       &lt;br /&gt;colors sampler pack         removed       removed       &lt;br /&gt;detectindent                removed       removed       &lt;br /&gt;doxygen-toolkit             removed       removed       &lt;br /&gt;editexisting                removed       removed       &lt;br /&gt;enhanced-commentify         removed       removed       &lt;br /&gt;gnupg                       removed       removed       &lt;br /&gt;info                        removed       removed       &lt;br /&gt;justify                     removed       removed       &lt;br /&gt;lbdbq                       removed       removed       &lt;br /&gt;markdown-syntax             removed       removed       &lt;br /&gt;matchit                     removed       removed       &lt;br /&gt;minibufexplorer             removed       removed       &lt;br /&gt;nerd-commenter              removed       removed       &lt;br /&gt;omnicppcomplete             removed       removed       &lt;br /&gt;po                          removed       removed       &lt;br /&gt;project                     removed       removed       &lt;br /&gt;python-indent               removed       removed       &lt;br /&gt;secure-modelines            removed       removed       &lt;br /&gt;snippetsEmu                 removed       removed       &lt;br /&gt;sokoban                     removed       removed       &lt;br /&gt;supertab                    removed       removed       &lt;br /&gt;surround                    removed       removed       &lt;br /&gt;taglist                     removed       removed       &lt;br /&gt;tetris                      removed       removed       &lt;br /&gt;utl                         removed       removed       &lt;br /&gt;vcscommand                  removed       removed       &lt;br /&gt;vimplate                    removed       removed       &lt;br /&gt;whatdomain                  removed       removed       &lt;br /&gt;winmanager                  removed       removed       &lt;br /&gt;xmledit                     removed       removed       &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The Taglist plugin is described here, while OmniCppComplete plugin in next section. Both of them make use of ctags utility. Install it first:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install exuberant-ctags&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now install the Taglist plugin to your Vim:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# vim-addons install taglist&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; When editing a supported file type, Show the taglist window can be opened by one of the following:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:Tlist&lt;br /&gt;:TlistOpen&lt;br /&gt;:TlistToggle&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Move your cursor between windows by &amp;lt;Ctrl-w&amp;gt;_w as usual. You may want to add a shortcut to toggle this feature. Add lines to your .vimrc file per official document:&lt;br /&gt;&lt;pre class="brush: plain"&gt;nnoremap &amp;lt;silent&amp;gt; &amp;lt;F5&amp;gt; :TlistUpdate&amp;lt;CR&amp;gt;&lt;br /&gt;nnoremap &amp;lt;silent&amp;gt; &amp;lt;F6&amp;gt; :TlistToggle&amp;lt;CR&amp;gt;&lt;/pre&gt;&amp;nbsp; &amp;nbsp; When your cursor hovers on a function, &amp;lt;Ctrl-]&amp;gt; takes you to its declaration, while &amp;lt;Ctrl-t&amp;gt; takes you back.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; More help:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help taglist-using&lt;br /&gt;:help taglist-options&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;5. Using OmniCppComplete:&lt;/b&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Vim include basic support for code completion. The simplest way is to use &amp;lt;Ctrl-p&amp;gt;. Vim will search your include headers and do insertion. See the screenshot:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/gonwan1985/5746665104/"&gt;&lt;img alt="vim_ctrlp" border="0" height="359" src="http://farm3.static.flickr.com/2300/5746665104_6f34e57521.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The include search path can be set by:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:set path &amp;lt;your_path&amp;gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; More help info:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help 'complete'&lt;br /&gt;:help ins-completion&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Next, Vim provides basic C language completion using ctags. No C++ is supported. Additional languages script can be found in Vim's autoload directory, say &lt;code&gt;/usr/share/vim/vim72/autoload&lt;/code&gt;. But you should generate necessary ctags index files first. For libc6 header files:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# cd ~/.vim &lt;br /&gt;# ctags --c-kinds=+p --fields=+aS --extra=+q -f libc /usr/include/* /usr/include/arpa/* /usr/include/bits/* /usr/include/sys/*&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; And add lines to .vimrc file:&lt;br /&gt;&lt;pre class="brush: plain"&gt;autocmd FileType c set omnifunc=ccomplete#Complete&lt;br /&gt;set tags +=~/.vim/libc&lt;br /&gt;set completeopt=longest,menu&lt;br /&gt;map &amp;lt;C-F12&amp;gt; :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .&amp;lt;CR&amp;gt;&lt;/pre&gt;&amp;nbsp; &amp;nbsp; Omni completion can be issued by &amp;lt;Ctrl-x&amp;gt;_&amp;lt;Ctrl-o&amp;gt;. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Screenshoot showing function prototype:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/gonwan1985/5746744228/"&gt;&lt;img alt="vim_omni_c1" border="0" height="359" src="http://farm4.static.flickr.com/3595/5746744228_68243a2ef3.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Screenshoot showing struct member completion:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/gonwan1985/5746200187/"&gt;&lt;img alt="vim_omni_c2" border="0" height="359" src="http://farm6.static.flickr.com/5228/5746200187_2f2cdcc857.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; More help info:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help ft-syntax-onmi&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Note, the &lt;code&gt;ccomplete&lt;/code&gt; does not work well in C++ completion. So we need to install &lt;code&gt;OmniCppComplete&lt;/code&gt; plugin:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# vim-addons install omnicppcomplete&amp;nbsp;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Generate ctags index for stdc++ and qt4:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# cd ~/.vim&lt;br /&gt;# ctags -R --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f qt4 /usr/include/qt4&lt;br /&gt;# ctags -R --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ -f stdcpp /usr/include/c++&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; And add lines to .vimrc file:&lt;br /&gt;&lt;pre class="brush: plain"&gt;set nocp&lt;br /&gt;filetype plugin on&lt;br /&gt;set tags +=~/.vim/libc&lt;br /&gt;set tags +=~/.vim/stdcpp&lt;br /&gt;set tags +=~/.vim/qt4&lt;br /&gt;set completeopt=longest,menu&lt;br /&gt;map &amp;lt;C-F12&amp;gt; :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .&amp;lt;CR&amp;gt;&lt;br /&gt;" OmniCppComplete Options&lt;br /&gt;let OmniCpp_ShowPrototypeInAbbr = 1  " function parameters&lt;br /&gt;let OmniCpp_MayCompleteScope = 1     " autocomplete after ::&lt;br /&gt;let OmniCpp_DefaultNamespaces = ["std", "_GLIBCXX_STD"]  " see :help omnicpp-faq&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You may encounter problems when completing STL functions. Refer to &lt;code&gt;:help omnicpp-faq&lt;/code&gt; and find the solution. Anyway, it works all good for me. Here're screenshots showing STL and Qt code completion:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/gonwan1985/5746625195/"&gt;&lt;img alt="vim_omni_cpp1" border="0" height="359" src="http://farm3.static.flickr.com/2301/5746625195_a63af8e1c9.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/gonwan1985/5746625207/"&gt;&lt;img alt="vim_omni_cpp2" border="0" height="359" src="http://farm4.static.flickr.com/3209/5746625207_e897a6e76d.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; More help:&lt;br /&gt;&lt;pre class="brush: plain"&gt;:help omnicpp-options&lt;br /&gt;:help omnicpp-features&lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Finally, the list of lines adding to my .vimrc file:&lt;br /&gt;&lt;pre class="brush: plain"&gt;set number&lt;br /&gt;"set autoindent&lt;br /&gt;"set expandtab&lt;br /&gt;"set tabstop=4&lt;br /&gt;"set shiftwidth=4&lt;br /&gt;set modeline&lt;br /&gt;&lt;br /&gt;" Taglist Options&lt;br /&gt;let Tlist_Exit_OnlyWindow = 1&lt;br /&gt;nnoremap &amp;lt;silent&amp;gt; &amp;lt;F5&amp;gt; :TlistUpdate&amp;lt;CR&amp;gt;&lt;br /&gt;nnoremap &amp;lt;silent&amp;gt; &amp;lt;F6&amp;gt; :TlistToggle&amp;lt;CR&amp;gt;&lt;br /&gt;&lt;br /&gt;set nocp&lt;br /&gt;filetype plugin on&lt;br /&gt;set tags +=~/.vim/libc&lt;br /&gt;set tags +=~/.vim/stdcpp&lt;br /&gt;set tags +=~/.vim/qt4&lt;br /&gt;set completeopt=longest,menu&lt;br /&gt;map &amp;lt;C-F12&amp;gt; :!ctags -R --c++-kinds=+p --fields=+iaS --extra=+q .&amp;lt;CR&amp;gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;" OmniCppComplete Options&lt;br /&gt;let OmniCpp_ShowPrototypeInAbbr = 1  " function parameters&lt;br /&gt;let OmniCpp_MayCompleteScope = 1     " autocomplete after ::&lt;br /&gt;let OmniCpp_DefaultNamespaces = ["std", "_GLIBCXX_STD"]  " see :help omnicpp-faq&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3571038557924475058?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3571038557924475058/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3571038557924475058&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3571038557924475058'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3571038557924475058'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/05/vim-tips-in-ubuntu-1004.html' title='Vim Tips in Ubuntu 10.04'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2300/5746665104_6f34e57521_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3893965338007178864</id><published>2011-05-08T04:53:00.006+08:00</published><updated>2011-07-16T01:22:23.042+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu 10.04 on EeePC 1015PX</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Got a new EeePC 1015PX this week. I just installed the netbook version of Ubuntu 10.04.2 and all devices are recognized. Only some small tweaks are needed:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Add the partner repository:&lt;/b&gt;&lt;br /&gt;Go to System --&amp;gt; Administration --&amp;gt; Software Sources --&amp;gt; Other Softwares tab, check the partner repository. Then software like Sun's JDK and Skype become available. Skype works fine with my webcam.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Tweak asus hotkeys:&lt;/b&gt;&lt;br /&gt;The volume and wireless hotkeys do not function by default. Here's the official solution in wiki. &lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo vi /etc/default/grub&lt;/pre&gt;Find &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; parameter and modify it as follow:&lt;br /&gt;&lt;pre class="brush: plain"&gt;GRUB_CMDLINE_LINUX_DEFAULT="quiet acpi_osi=Linux acpi_backlight=vendor splash"&lt;/pre&gt;Then update grub installation with the command and reboot:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo update-grub&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;3. Disable Touchpad:&lt;/b&gt;&lt;br /&gt;It's necessary to disable the touchpad while typing. It annoying because it's always mis-clicked and cause input focus to move away. Many threads in forums discussed about this, but none works for me. The .32 kernel just recognizes the touchpad as a mouse, thus cannot be disabled. Then I just install the .35 kernel in the backport repository:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install linux-image-2.6.35-25-generic&lt;/pre&gt;After reboot into the new kernel, run:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# xinput list&lt;/pre&gt;The touchpad finally recognized correctly. Then continue installation:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install gsynaptics&lt;/pre&gt;Go to Preference --&amp;gt; Touchpad, uncheck "Enable touchpad".&lt;br /&gt;Go to Preference --&amp;gt; Mouse --&amp;gt; Touchpad tab, uncheck "Disable touchpad while typing". If this option is not disabled, your touchpad will be enabled after you type something.&lt;br /&gt;&lt;b&gt;Update July 15, 2011&lt;/b&gt;: Newer .32 kernels from 2.6.32-33 recognize the touchpad correctly. So if you use later versions or fresh install your ubuntu from 10.04.3, there's no need to install .35 kernel.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Autohide top panel:&lt;/b&gt;&lt;br /&gt;I installed the netbook UI by:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install ubuntu-netbook&lt;/pre&gt;There's no autohide property in the context menu of top panel of the UI. I had to modify it manually:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gconftool-2 -t bool -s /apps/panel/toplevels/top_panel/auto_hide true&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;5. Hide menu/bookmark bar in firefox:&lt;/b&gt;&lt;br /&gt;Too small content area in firefox by default. To hide bookmark bar, just find and uncheck the option in View menu. To hide menu bar, you need to install an extension called "Compact Menu 2". It compacts the whole menu as a single button in navigation bar. In addition, you may also want to disable the "webfav" extension to make room.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;6. Adjust screen panning:&lt;/b&gt;&lt;br /&gt;Some application is not netbook-friendly. Their windows are just to large, even beyond 1024x600. To view the whole window, you can set the logic resolution of your screen. And it scrolls when your mouse pointer reaches the border of the physical screen. First, find the output of your screen by:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# xrandr -q&lt;/pre&gt;The current output name may be VGA*, LVDS* or else. Then change your logic resolution of it like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# xrandr --output LVDS1 --panning 1280x800&lt;br /&gt;# xrandr --output LVDS1 --panning 1024x600&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;7. Tweak startup applications:&lt;/b&gt;&lt;br /&gt;Go to System --&amp;gt; Preferences --&amp;gt; Startup Applications, uncheck unnecessary items. For me, they are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Evolution Mail Notifier (unused)&lt;/li&gt;&lt;li&gt;Print Queue Applet (unused)&lt;/li&gt;&lt;li&gt;Visual Assistance (unused)&lt;/li&gt;&lt;li&gt;Bluetooth Manager (no bluetooth device)&lt;/li&gt;&lt;li&gt;Maximus Window Management (no need to the feature)&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;8. Make Vim your text reader:&lt;/b&gt;&lt;br /&gt;I read novels in text files, I want to keep track of the last reading position automatically.&lt;br /&gt;&lt;pre class="brush: plain"&gt;# cp /etc/vim/vimrc ~/.vimrc&lt;br /&gt;# vi ~/.vimrc&lt;/pre&gt;Search and uncomment the line as guided:&lt;br /&gt;&lt;pre class="brush: plain"&gt;" Uncomment the following to have Vim jump to the last position when&lt;br /&gt;" reopening a file&lt;br /&gt;if has("autocmd")&lt;br /&gt;  au BufReadPost * if line("'\"") &amp;gt; 1 &amp;amp;&amp;amp; line("'\"") &amp;lt;= line("$") | exe "normal! g'\"" | endif&lt;br /&gt;endif&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;9. Switch between gcc versions:&lt;/b&gt;&lt;br /&gt;Sometimes, a specific version of gcc/g++ is needed to build a project. I simplify this by making use of the "update-alternative" utility. Suppose you have installed gcc-4.1 and gcc-4.4:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.1 10&lt;br /&gt;# sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.4 40&lt;br /&gt;# sudo update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-4.1 10&lt;br /&gt;# sudo update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-4.4 40&lt;/pre&gt;Then you can switch versions by:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo update-alternatives --config gcc&lt;br /&gt;# sudo update-alternatives --config cpp&lt;/pre&gt;Actually, other less used symbolic links also need configure like this. They are gcov, i486-linux-gnu-gcc, i486-linux-gnu-cpp.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3893965338007178864?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3893965338007178864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3893965338007178864&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3893965338007178864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3893965338007178864'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/05/ubuntu-1004-on-eeepc-1015px.html' title='Ubuntu 10.04 on EeePC 1015PX'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1334292569849441563</id><published>2011-03-28T17:51:00.001+08:00</published><updated>2011-03-28T17:55:11.831+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Debug'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Debug Qt Libraries with Ubuntu Debug Packages</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; In previous &lt;a href="http://gonwan1985.blogspot.com/2010/07/using-ubuntu-debug-packages-in-gdb-2.html"&gt;articles&lt;/a&gt;, I was not able to use Qt's debug package provided by Ubuntu. Now, I will explain how to use them.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Our simple application:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;// main.cpp&lt;br /&gt;#include &amp;lt;QtCore/QString&amp;gt;&lt;br /&gt;int main() {&lt;br /&gt;    QString s = "1234567";&lt;br /&gt;    int i = s.indexOf('3');&lt;br /&gt;    return i != 2;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Our *.pro file, you should enable the debug build:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# DebugQt.pro&lt;br /&gt;TARGET = DebugQt&lt;br /&gt;TEMPLATE = app&lt;br /&gt;SOURCES += main.cpp&lt;br /&gt;QT -= gui&lt;br /&gt;CONFIG += console debug_and_release&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1. Build your debug version of application:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# qmake-qt4&lt;br /&gt;# make debug&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2. Install Qt's debug package:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install libqt4-debug&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3. Install the Qt source:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get source libqt4-debug&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now you can start debugging your application. Since Qt's debug symbols are installed in /usr/lib, It does not follow the GDB's global debug directory described &lt;a href="http://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html"&gt;here&lt;/a&gt;. We should tell GDB to load these symbols manually:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gdb ./DebugQt&lt;br /&gt;GNU gdb 6.8-debian&lt;br /&gt;...&lt;br /&gt;(gdb) b main&lt;br /&gt;Breakpoint 1 at 0x8048696: file main.cpp, line 3.&lt;br /&gt;(gdb) r&lt;br /&gt;Starting program: /home/binson/DebugQt/DebugQt &lt;br /&gt;[Thread debugging using libthread_db enabled]&lt;br /&gt;[New Thread 0xb71d36c0 (LWP 11138)]&lt;br /&gt;[Switching to Thread 0xb71d36c0 (LWP 11138)]&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at main.cpp:3&lt;br /&gt;3     QString s = "1234567";&lt;br /&gt;(gdb) info sharedlibrary&lt;br /&gt;From        To          Syms Read   Shared Object Library&lt;br /&gt;0xb77a47f0  0xb77b96df  Yes         /lib/ld-linux.so.2&lt;br /&gt;0xb7652510  0xb7740904  Yes         /usr/lib/libQtCore.so.4&lt;br /&gt;0xb7605210  0xb7610a04  Yes         /lib/tls/i686/cmov/libpthread.so.0&lt;br /&gt;0xb754fa60  0xb75ccb14  Yes         /usr/lib/libstdc++.so.6&lt;br /&gt;0xb74eb440  0xb7505414  Yes         /lib/tls/i686/cmov/libm.so.6&lt;br /&gt;0xb74de970  0xb74e5e04  Yes         /lib/libgcc_s.so.1&lt;br /&gt;0xb73a4230  0xb74a4ea4  Yes         /lib/tls/i686/cmov/libc.so.6&lt;br /&gt;0xb7368470  0xb7380684  Yes         /usr/lib/libfontconfig.so.1&lt;br /&gt;0xb7350910  0xb735e3e4  Yes         /usr/lib/libz.so.1&lt;br /&gt;0xb734a180  0xb734b804  Yes         /usr/lib/libgthread-2.0.so.0&lt;br /&gt;0xb7341990  0xb7345ee4  Yes         /lib/tls/i686/cmov/librt.so.1&lt;br /&gt;0xb72a0620  0xb72fe114  Yes         /usr/lib/libglib-2.0.so.0&lt;br /&gt;0xb728ba70  0xb728ca74  Yes         /lib/tls/i686/cmov/libdl.so.2&lt;br /&gt;0xb72249f0  0xb7276264  Yes         /usr/lib/libfreetype.so.6&lt;br /&gt;0xb71fe190  0xb7214384  Yes         /usr/lib/libexpat.so.1&lt;br /&gt;0xb71d5ef0  0xb71f1da4  Yes         /usr/lib/libpcre.so.3&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; We set a breakpoint at the beginning of main function to load all shared libraries. Next, we will load symbols for libQtCore.so.4. The symbol will be loaded in the start address of it (0xb7652510):&lt;br /&gt;&lt;pre class="brush: plain"&gt;(gdb) add-symbol-file /usr/lib/libQtCore.so.4.3.4.debug 0xb7652510&lt;br /&gt;add symbol table from file "/usr/lib/libQtCore.so.4.3.4.debug" at&lt;br /&gt; .text_addr = 0xb7652510&lt;br /&gt;(y or n) y&lt;br /&gt;Reading symbols from /usr/lib/libQtCore.so.4.3.4.debug...done.&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now, you are able to step into the Qt library, but no source is attached:&lt;br /&gt;&lt;pre class="brush: plain"&gt;(gdb) b 4&lt;br /&gt;Breakpoint 2 at 0x80486a9: file main.cpp, line 4.&lt;br /&gt;(gdb) c&lt;br /&gt;Continuing.&lt;br /&gt;&lt;br /&gt;Breakpoint 2, main () at main.cpp:4&lt;br /&gt;4     int i = s.indexOf('3');&lt;br /&gt;(gdb) s&lt;br /&gt;QChar (this=0xbfb1ec0e, ch=51 '3') at tools/qchar.cpp:432&lt;br /&gt;432 tools/qchar.cpp: No such file or directory.&lt;br /&gt; in tools/qchar.cpp&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Source files are attached by:&lt;br /&gt;&lt;pre class="brush: plain"&gt;(gdb) dir ~/qt4-x11-4.3.4/src/corelib&lt;br /&gt;Source directories searched: /home/binson/qt4-x11-4.3.4/src/corelib:$cdir:$cwd&lt;br /&gt;(gdb) l&lt;br /&gt;427 &lt;br /&gt;428 /*!&lt;br /&gt;429     Constructs a QChar corresponding to ASCII/Latin-1 character \a&lt;br /&gt;430     ch.&lt;br /&gt;431 */&lt;br /&gt;432 QChar::QChar(char ch)&lt;br /&gt;433 {&lt;br /&gt;434 #ifndef QT_NO_CODEC_FOR_C_STRINGS&lt;br /&gt;435     if (QTextCodec::codecForCStrings())&lt;br /&gt;436         // #####&lt;br /&gt;(gdb) bt&lt;br /&gt;#0  QChar (this=0xbfb1ec0e, ch=51 '3') at tools/qchar.cpp:432&lt;br /&gt;#1  0x080486bc in main () at main.cpp:4&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; See the source and backtrace? :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1334292569849441563?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1334292569849441563/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1334292569849441563&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1334292569849441563'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1334292569849441563'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/debug-qt-libraries-with-ubuntu-debug.html' title='Debug Qt Libraries with Ubuntu Debug Packages'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5482867461548700755</id><published>2011-03-13T19:09:00.006+08:00</published><updated>2011-03-15T17:34:06.761+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OO Impelementation in C#</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Finally, we comes with the C# language. C# supports all OO features mentioned in previous articles in language level. So, our implementation is quite straight forward. Just check the source code in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestCSObject-{date}.zip file. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Lastly, I drew a simple table to compare and summarize the OO supports in the four leading languages:&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="text-align: center; width: 700px;"&gt; &lt;tbody&gt;&lt;tr&gt;   &lt;td style="width: 120px;"&gt;&amp;nbsp;   &lt;/td&gt;   &lt;td style="width: 130px;"&gt;C/gtk+   &lt;/td&gt;   &lt;td style="width: 160px;"&gt;C++/Qt   &lt;/td&gt;   &lt;td style="width: 130px;"&gt;Java   &lt;/td&gt;   &lt;td style="width: 180px;"&gt;C#   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;&amp;nbsp;   &lt;/td&gt;   &lt;td colspan="4"&gt;Basic Features   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Encapsulation   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library   &lt;/td&gt;   &lt;td style="background-color: red;"&gt;good design   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Inheritance   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Polymorphism   &lt;/td&gt;   &lt;td style="background-color: red;"&gt;function pointer   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;&amp;nbsp;   &lt;/td&gt;   &lt;td colspan="4"&gt;Advanced Features   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Property   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library   &lt;/td&gt;   &lt;td style="background-color: red;"&gt;reflection feature   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;Y   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Meta Info   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;annotations   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;attributes   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Event Driven   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library(signals)   &lt;/td&gt;   &lt;td style="background-color: #ffc000;"&gt;library(signals/slots)   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;events/listeners   &lt;/td&gt;   &lt;td style="background-color: #92d050;"&gt;delegates/events/handlers   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;&amp;nbsp;   &lt;/td&gt;   &lt;td colspan="4"&gt;Measurements (Using a test application to demostrate above 5 features)   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Compiler   &lt;/td&gt;   &lt;td&gt;mingw32-gcc/3.4   &lt;/td&gt;   &lt;td&gt;mingw32-g++/3.4   &lt;/td&gt;   &lt;td&gt;JDK/1.6.20   &lt;/td&gt;   &lt;td&gt;VC#/2005   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Library   &lt;/td&gt;   &lt;td&gt;gtk+/2.16.6   &lt;/td&gt;   &lt;td&gt;Qt/4.3.5   &lt;/td&gt;   &lt;td&gt;Java/6.0   &lt;/td&gt;   &lt;td&gt;.NET/2.0   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Source Size   &lt;/td&gt;   &lt;td&gt;19.09 KB   &lt;/td&gt;   &lt;td&gt;7.28 KB (+10.17 KB) *   &lt;/td&gt;   &lt;td&gt;13.18 KB   &lt;/td&gt;   &lt;td&gt;6.28 KB   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Binary Size   &lt;/td&gt;   &lt;td&gt;32.69 KB   &lt;/td&gt;   &lt;td&gt;34.00 KB   &lt;/td&gt;   &lt;td&gt;9.48 KB   &lt;/td&gt;   &lt;td&gt;5.50 KB   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td&gt;Runtime Size   &lt;/td&gt;   &lt;td&gt;1.46 MB   &lt;/td&gt;   &lt;td&gt;2.00 MB   &lt;/td&gt;   &lt;td&gt;15.54 MB   &lt;/td&gt;   &lt;td&gt;23.84 MB   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td colspan="5" style="text-align: left;"&gt;&amp;nbsp;   &lt;/td&gt;  &lt;/tr&gt;&lt;tr&gt;   &lt;td colspan="5" style="text-align: left;"&gt;* Generated source   &lt;/td&gt;  &lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;ul&gt;Here's the complete list of all articles regarding OO implementation in C, C++, Java &amp;amp; C#:&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-1-fundamental-type.html"&gt;OOP Using GObject (1) - A Fundamental Type&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-2-classed-type.html"&gt;OOP Using GObject (2) - A Classed Type&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-3-instantiatable.html"&gt;OOP Using GObject (3) - An Instantiatable Class&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-4-inheritable-class.html"&gt;OOP Using GObject (4) - An Inheritable Class&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-5-private-members.html"&gt;OOP Using GObject (5) - Private Members&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-6-properties.html"&gt;OOP Using GObject (6) - Properties&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-7-signals.html"&gt;OOP Using GObject (7) - Signals&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-8-interface.html"&gt;OOP Using GObject (8) - An interface&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-9-dynamic-type.html"&gt;OOP Using GObject (9) - A Dynamic Type&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oo-impelementation-in-c.html"&gt;OO Impelementation in C++&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oo-impelementation-in-java.html"&gt;OO Impelementation in Java&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://gonwan1985.blogspot.com/2011/03/oo-impelementation-in-c_13.html"&gt;OO Impelementation in C#&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5482867461548700755?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5482867461548700755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5482867461548700755&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5482867461548700755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5482867461548700755'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oo-impelementation-in-c_13.html' title='OO Impelementation in C#'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-7958207410758714602</id><published>2011-03-13T18:40:00.002+08:00</published><updated>2011-03-15T16:42:32.622+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Property'/><category scheme='http://www.blogger.com/atom/ns#' term='Annotation'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OO Impelementation in Java</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Continue with last article, we will try to write an identical application to use OO features including: encapsulation, inheritance, polymorphism, properties, meta info and event-driven mechanism. Java supports the 3 basic features in language level. It uses interfaces to implements event-driven. To implements properties and meta info, we have to write our own code. We want to implements API like &lt;code&gt;someObject.setProperty(prop-name, prop-value)&lt;/code&gt;. I write my own &lt;code&gt;NewObject&lt;/code&gt; class:&lt;br /&gt;&lt;pre class="brush: java"&gt;package my;&lt;br /&gt;&lt;br /&gt;import java.lang.reflect.Field;&lt;br /&gt;import java.lang.reflect.InvocationTargetException;&lt;br /&gt;import java.lang.reflect.Method;&lt;br /&gt;&lt;br /&gt;import my.annotation.ClassInfo;&lt;br /&gt;import my.annotation.ClassInfoList;&lt;br /&gt;import my.annotation.Property;&lt;br /&gt;import my.annotation.PropertyAccess;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * We just set/get values as Object type. End users know the exact type of the&lt;br /&gt; * property, and they can do the conversion themselves.&lt;br /&gt; */&lt;br /&gt;public class NewObject {&lt;br /&gt;&lt;br /&gt;    private static String makeGetPropertyName(Field field) {&lt;br /&gt;        String fieldName = field.getName();&lt;br /&gt;        if (fieldName == null || fieldName.equals("")) {&lt;br /&gt;            return null;&lt;br /&gt;        }&lt;br /&gt;        return "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static String makeSetPropertyName(Field field) {&lt;br /&gt;        String fieldName = field.getName();&lt;br /&gt;        if (fieldName == null || fieldName.equals("")) {&lt;br /&gt;            return null;&lt;br /&gt;        }&lt;br /&gt;        return "set" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Get property&lt;br /&gt;     * @param name&lt;br /&gt;     * @return&lt;br /&gt;     */&lt;br /&gt;    public Object getProperty(String name) {&lt;br /&gt;        Class klass = this.getClass();&lt;br /&gt;        Field field = null;&lt;br /&gt;        while (!klass.getName().equals(NewObject.class.getName())) {&lt;br /&gt;            try {&lt;br /&gt;                field = klass.getDeclaredField(name);&lt;br /&gt;                break;  // found&lt;br /&gt;            } catch (NoSuchFieldException e) {&lt;br /&gt;                // noop&lt;br /&gt;            }&lt;br /&gt;            klass = klass.getSuperclass();&lt;br /&gt;        }&lt;br /&gt;        if (field != null) {&lt;br /&gt;            Property property = field.getAnnotation(Property.class);&lt;br /&gt;            if (property.value() == PropertyAccess.WRITE&lt;br /&gt;                    || property.value() == PropertyAccess.READWRITE) {&lt;br /&gt;                String methodName = makeGetPropertyName(field);&lt;br /&gt;                try {&lt;br /&gt;                    /**&lt;br /&gt;                     * We can also get the value directly as below, but this&lt;br /&gt;                     * bypass the getter function which is wrong. &lt;br /&gt;                     * &amp;lt;code&amp;gt;&lt;br /&gt;                     * field.setAccessible(true);&lt;br /&gt;                     * Object value = field.get(this);&lt;br /&gt;                     * field.setAccessible(false);&lt;br /&gt;                     * return value;&lt;br /&gt;                     * &amp;lt;/code&amp;gt;&lt;br /&gt;                     */&lt;br /&gt;                    Method getMethod = klass.getMethod(methodName);&lt;br /&gt;                    return getMethod.invoke(this);&lt;br /&gt;                } catch (IllegalAccessException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (IllegalArgumentException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (InvocationTargetException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (NoSuchMethodException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (SecurityException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Set property&lt;br /&gt;     * @param name&lt;br /&gt;     * @param value&lt;br /&gt;     */&lt;br /&gt;    public void setProperty(String name, Object value) {&lt;br /&gt;        Class klass = this.getClass();&lt;br /&gt;        Field field = null;&lt;br /&gt;        while (!klass.getName().equals(NewObject.class.getName())) {&lt;br /&gt;            try {&lt;br /&gt;                field = klass.getDeclaredField(name);&lt;br /&gt;                break;  // found&lt;br /&gt;            } catch (NoSuchFieldException e) {&lt;br /&gt;                // noop&lt;br /&gt;            }&lt;br /&gt;            klass = klass.getSuperclass();&lt;br /&gt;        }&lt;br /&gt;        if (field != null) {&lt;br /&gt;            Property property = field.getAnnotation(Property.class);&lt;br /&gt;            if (property.value() == PropertyAccess.WRITE&lt;br /&gt;                    || property.value() == PropertyAccess.READWRITE) {&lt;br /&gt;                String methodName = makeSetPropertyName(field);&lt;br /&gt;                try {&lt;br /&gt;                    Method setMethod = klass.getMethod(methodName, field.getType());&lt;br /&gt;                    setMethod.invoke(this, value);&lt;br /&gt;                } catch (IllegalAccessException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (IllegalArgumentException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (InvocationTargetException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (NoSuchMethodException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                } catch (SecurityException e) {&lt;br /&gt;                    // noop&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Dump class info by given class&lt;br /&gt;     * @param klass&lt;br /&gt;     */&lt;br /&gt;    public static void dumpClassInfo(Class klass) {&lt;br /&gt;        System.out.println(klass.getCanonicalName() + "(");&lt;br /&gt;        ClassInfo[] klassInfos = klass.getAnnotation(ClassInfoList.class).value();&lt;br /&gt;        for (int i = 0; i &amp;lt; klassInfos.length; i++) {&lt;br /&gt;            System.out.println(klassInfos[i].name() + "=" + klassInfos[i].value());&lt;br /&gt;        }&lt;br /&gt;        System.out.println(")");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Dump class info of current object&lt;br /&gt;     */&lt;br /&gt;    public void dumpClassInfo() {&lt;br /&gt;        Class klass = this.getClass();&lt;br /&gt;        System.out.println(klass.getCanonicalName() + "(");&lt;br /&gt;        ClassInfo[] klassInfos = klass.getAnnotation(ClassInfoList.class).value();&lt;br /&gt;        for (int i = 0; i &amp;lt; klassInfos.length; i++) {&lt;br /&gt;            System.out.println(klassInfos[i].name() + "=" + klassInfos[i].value());&lt;br /&gt;        }&lt;br /&gt;        System.out.println(")");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Get class info by given name&lt;br /&gt;     * @param name&lt;br /&gt;     * @return&lt;br /&gt;     */&lt;br /&gt;    public String getClassInfo(String name) {&lt;br /&gt;        Class klass = this.getClass();&lt;br /&gt;        ClassInfo[] klassInfos = klass.getAnnotation(ClassInfoList.class).value();&lt;br /&gt;        for (int i = 0; i &amp;lt; klassInfos.length; i++) {&lt;br /&gt;            if (klassInfos[i].name().equals(name)) {&lt;br /&gt;                return klassInfos[i].value();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; To use our &lt;code&gt;setProperty()&lt;/code&gt;/&lt;code&gt;getProperty()&lt;/code&gt; method, all classes should derive from the &lt;code&gt;NewObject&lt;/code&gt; class. To be consistent with the JavaBean convention, we assume that the getter/setter function to be "get"/"set" + capitalize_first_letter_of(member-variable-name). &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;Property&lt;/code&gt; annotation and &lt;code&gt;PropertyAccess&lt;/code&gt; enum are defined to indicate properties:&lt;br /&gt;&lt;pre class="brush: java"&gt;// PropertyAccess.java&lt;br /&gt;package my.annotation;&lt;br /&gt;&lt;br /&gt;public enum PropertyAccess {&lt;br /&gt;    READ, WRITE, READWRITE&lt;br /&gt;}&lt;/pre&gt;&lt;pre class="brush: java"&gt;// Property.java&lt;br /&gt;package my.annotation;&lt;br /&gt;&lt;br /&gt;import java.lang.annotation.ElementType;&lt;br /&gt;import java.lang.annotation.Retention;&lt;br /&gt;import java.lang.annotation.RetentionPolicy;&lt;br /&gt;import java.lang.annotation.Target;&lt;br /&gt;&lt;br /&gt;@Retention(RetentionPolicy.RUNTIME)&lt;br /&gt;@Target(ElementType.FIELD)&lt;br /&gt;public @interface Property {&lt;br /&gt;    /* "value" seems to be a magic name */&lt;br /&gt;    public PropertyAccess value();&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;ClassInfo&lt;/code&gt; and &lt;code&gt;ClassInfoList&lt;/code&gt; annotation are defined to indicate class meta info:&lt;br /&gt;&lt;pre class="brush: java"&gt;// ClassInfo.java&lt;br /&gt;package my.annotation;&lt;br /&gt;&lt;br /&gt;import java.lang.annotation.ElementType;&lt;br /&gt;import java.lang.annotation.Retention;&lt;br /&gt;import java.lang.annotation.RetentionPolicy;&lt;br /&gt;import java.lang.annotation.Target;&lt;br /&gt;&lt;br /&gt;@Retention(RetentionPolicy.RUNTIME)&lt;br /&gt;@Target(ElementType.TYPE)&lt;br /&gt;public @interface ClassInfo {&lt;br /&gt;    public String name();&lt;br /&gt;    public String value();&lt;br /&gt;}&lt;/pre&gt;&lt;pre class="brush: java"&gt;// ClassInfoList.java&lt;br /&gt;package my.annotation;&lt;br /&gt;&lt;br /&gt;import java.lang.annotation.ElementType;&lt;br /&gt;import java.lang.annotation.Retention;&lt;br /&gt;import java.lang.annotation.RetentionPolicy;&lt;br /&gt;import java.lang.annotation.Target;&lt;br /&gt;&lt;br /&gt;@Retention(RetentionPolicy.RUNTIME)&lt;br /&gt;@Target(ElementType.TYPE)&lt;br /&gt;public @interface ClassInfoList {&lt;br /&gt;    ClassInfo[] value();&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Let's see how to use them, our &lt;code&gt;Base&lt;/code&gt; is defined as:&lt;br /&gt;&lt;pre class="brush: java"&gt;// Base.java&lt;br /&gt;package fake;&lt;br /&gt;&lt;br /&gt;import java.util.LinkedList;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;import my.NewObject;&lt;br /&gt;import my.annotation.ClassInfo;&lt;br /&gt;import my.annotation.ClassInfoList;&lt;br /&gt;import my.annotation.Property;&lt;br /&gt;import my.annotation.PropertyAccess;&lt;br /&gt;&lt;br /&gt;@ClassInfoList({ &lt;br /&gt;    @ClassInfo(name = "author", value = "gonwan"),&lt;br /&gt;    @ClassInfo(name = "version", value = "1.0.0") &lt;br /&gt;})&lt;br /&gt;public class Base extends NewObject {&lt;br /&gt;    @Property(PropertyAccess.READWRITE)&lt;br /&gt;    private int id;&lt;br /&gt;    @Property(PropertyAccess.READWRITE)&lt;br /&gt;    private String name;&lt;br /&gt;&lt;br /&gt;    private List&amp;lt;IPrintInt&amp;gt; basePrintIntListeners;&lt;br /&gt;    private List&amp;lt;IPrintString&amp;gt; basePrintStringListeners;&lt;br /&gt;&lt;br /&gt;    public Base() {&lt;br /&gt;        basePrintIntListeners = new LinkedList&amp;lt;IPrintInt&amp;gt;();&lt;br /&gt;        basePrintStringListeners = new LinkedList&amp;lt;IPrintString&amp;gt;();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getId() {&lt;br /&gt;        return id;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setId(int id) {&lt;br /&gt;        this.id = id;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public String getName() {&lt;br /&gt;        return name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void setName(String name) {&lt;br /&gt;        this.name = name;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void virtualDump() {&lt;br /&gt;        System.out.printf("Base(virtual): id=%d, name=\"%s\"\n", getId(), getName());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    final public void nonvirtualDump() {&lt;br /&gt;        System.out.printf("Base(nonvirtual): id=%d, name=\"%s\"\n", getId(), getName());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void addBasePrintIntListener(IPrintInt listener) {&lt;br /&gt;        basePrintIntListeners.add(listener);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void addBasePrintStringListener(IPrintString listener) {&lt;br /&gt;        basePrintStringListeners.add(listener);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void fireBasePrintIntEvent(int i) {&lt;br /&gt;        for (IPrintInt listener : basePrintIntListeners) {&lt;br /&gt;            listener.printInt(i);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void fireBasePrintStringEvent(String str) {&lt;br /&gt;        for (IPrintString listener : basePrintStringListeners) {&lt;br /&gt;            listener.PrintString(str);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Since our implementation of properties are simply methods, they can be inherited by subclasses. But the class meta info cannot be retrieved in subclasses. They just get their own. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I do not want to demo events/listeners code here, just find them in source code in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestJavaObject-{date}.zip file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-7958207410758714602?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/7958207410758714602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=7958207410758714602&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7958207410758714602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7958207410758714602'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oo-impelementation-in-java.html' title='OO Impelementation in Java'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-7910918943740188319</id><published>2011-03-13T17:51:00.001+08:00</published><updated>2011-03-15T16:42:54.893+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>OO Impelementation in C++</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; From the last series of GObject library, we know the approach of OOP using C. Now, I just want to have a comparison of OO implementation in all leading programming languages: C, C++, Java and C#. I will use C++/Qt in this article. Apart from basic features like encapsulation, inheritance, polymorphism, I will demonstrate how to use advanced features including properties, meta info and event-driven programming.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now, let's start. Since C++ supports inheritance and polymorphism in language level. They are not the problem. When encounter encapsulation, it does not do well. We CAN declare member variables as private to prohibit their directly access. But the internal implementation is still exposed. When adding/removing private member variables, the class structure is changed. This can cause binary compatible issues. According to the guide of Qt, we define a private class to hold all private member variables, and add the pointer of it to our public class. The size of pointer is constant in all platforms, so this will not break the binary compatibility. Here's the code:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: To use Qt's object mechanism, your class should inherit &lt;code&gt;QObject&lt;/code&gt; class and include the &lt;code&gt;Q_OBJECT&lt;/code&gt; macro.&lt;br /&gt;&lt;pre class="brush: cpp"&gt;// qfakebase.h&lt;br /&gt;#ifndef QFAKEBASE_H&lt;br /&gt;#define QFAKEBASE_H&lt;br /&gt;&lt;br /&gt;#include &amp;lt;QtCore/QObject&amp;gt;&lt;br /&gt;#include &amp;lt;QtCore/QString&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;namespace Fake {&lt;br /&gt;&lt;br /&gt;class QBasePrivate;&lt;br /&gt;&lt;br /&gt;class QBase : public QObject&lt;br /&gt;{&lt;br /&gt;    Q_OBJECT&lt;br /&gt;    Q_DECLARE_PRIVATE(QBase)&lt;br /&gt;    Q_CLASSINFO("Author", "gonwan")&lt;br /&gt;    Q_CLASSINFO("Version", "1.0.0")&lt;br /&gt;    Q_PROPERTY(int id READ id WRITE setId)&lt;br /&gt;    Q_PROPERTY(QString name READ name WRITE setName)&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    explicit QBase(QObject *parent=0);&lt;br /&gt;    virtual ~QBase();&lt;br /&gt;    int id();&lt;br /&gt;    void setId(int id);&lt;br /&gt;    QString name();&lt;br /&gt;    void setName(QString name);&lt;br /&gt;    virtual void virtualDump();&lt;br /&gt;    void nonvirtualDump();&lt;br /&gt;    /*&lt;br /&gt;     * All signals are defined protected, they can be only emit by&lt;br /&gt;     * themselves or their subclasses. So we add these two help function&lt;br /&gt;     * to help to emit our singals.&lt;br /&gt;     */&lt;br /&gt;    void emitBasePrintInt(int i);&lt;br /&gt;    void emitBasePrintString(QString str);&lt;br /&gt;&lt;br /&gt;protected:&lt;br /&gt;    QBasePrivate *const d_ptr;&lt;br /&gt;&lt;br /&gt;signals:&lt;br /&gt;    void basePrintInt(int i);&lt;br /&gt;    void basePrintString(QString str);&lt;br /&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;}  // namespace Fake&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif // QFAKEBASE_H&lt;/pre&gt;&lt;pre class="brush: cpp"&gt;// qfakebase.c&lt;br /&gt;#include "qfakebase.h"&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;namespace Fake {&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* private class */&lt;br /&gt;class QBasePrivate&lt;br /&gt;{&lt;br /&gt;    //Q_DECLARE_PUBLIC(QBase)&lt;br /&gt;public:&lt;br /&gt;    int id;&lt;br /&gt;    QString name;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/* public class */&lt;br /&gt;QBase::QBase(QObject *parent)&lt;br /&gt;    : QObject(parent), d_ptr(new QBasePrivate) {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;QBase::~QBase() {&lt;br /&gt;    delete d_ptr;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int QBase::id() {&lt;br /&gt;    Q_D(QBase);&lt;br /&gt;    return d-&amp;gt;id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void QBase::setId(int id) {&lt;br /&gt;    Q_D(QBase);&lt;br /&gt;    d-&amp;gt;id = id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;QString QBase::name() {&lt;br /&gt;    Q_D(QBase);&lt;br /&gt;    return d-&amp;gt;name;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void QBase::setName(QString name) {&lt;br /&gt;    Q_D(QBase);&lt;br /&gt;    d-&amp;gt;name = name;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void QBase::virtualDump() {&lt;br /&gt;    printf("QBase(virtual): id=%d, name=\"%s\"\n", id(), qPrintable(name()));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void QBase::nonvirtualDump() {&lt;br /&gt;    printf("QBase(nonvirtual): id=%d, name=\"%s\"\n", id(), qPrintable(name()));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void QBase::emitBasePrintInt(int i) {&lt;br /&gt;    emit basePrintInt(i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void QBase::emitBasePrintString(QString str) {&lt;br /&gt;    emit basePrintString(str);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;}  // namespace Fake&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Just note the forward declaration of &lt;code&gt;QBasePrivate&lt;/code&gt; private class. It is define in *.c file, and cannot be used by client applications. We defined a &lt;code&gt;d_ptr&lt;/code&gt; protected member variable of this type to hold all private data values. Qt library provideds a series of easy-to-use macros to support this scheme to implementation:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;// qglobal.h&lt;br /&gt;#define Q_DECLARE_PRIVATE(Class) \&lt;br /&gt;    inline Class##Private* d_func() { return reinterpret_cast&amp;lt;Class##Private *&amp;gt;(d_ptr); } \&lt;br /&gt;    inline const Class##Private* d_func() const { return reinterpret_cast&amp;lt;const Class##Private *&amp;gt;(d_ptr); } \&lt;br /&gt;    friend class Class##Private;&lt;br /&gt;&lt;br /&gt;#define Q_DECLARE_PUBLIC(Class) \&lt;br /&gt;    inline Class* q_func() { return static_cast&amp;lt;Class *&amp;gt;(q_ptr); } \&lt;br /&gt;    inline const Class* q_func() const { return static_cast&amp;lt;const Class *&amp;gt;(q_ptr); } \&lt;br /&gt;    friend class Class;&lt;br /&gt;&lt;br /&gt;#define Q_D(Class) Class##Private * const d = d_func()&lt;br /&gt;#define Q_Q(Class) Class * const q = q_func()&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Qt library supports properties and meta info. properties are defined with &lt;code&gt;Q_PROPERTY&lt;/code&gt;macro, while class meta info are defined with &lt;code&gt;Q_CLASSINFO&lt;/code&gt;. Both of them can be inherited by derived classes. Last is Qt's event-driven mechanism: signals/slots. Since they are also based on &lt;code&gt;QObject&lt;/code&gt;, we had to define a test class to include all slots:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;// mytestclass.h&lt;br /&gt;#ifndef MYTESTCLASS_H&lt;br /&gt;#define MYTESTCLASS_H&lt;br /&gt;&lt;br /&gt;#include &amp;lt;QtCore/QObject&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * Qt's signal/slot mechanism only works with&lt;br /&gt; * QObject-derived classes. So we define a test class here.&lt;br /&gt; */&lt;br /&gt;class MyTestClass : public QObject {&lt;br /&gt;    Q_OBJECT&lt;br /&gt;public slots:&lt;br /&gt;    void printInt1(int i) {&lt;br /&gt;        QString name = sender()-&amp;gt;metaObject()-&amp;gt;className();&lt;br /&gt;        printf("Invoking printInt1(): %s.i=%d\n", qPrintable(name), i);&lt;br /&gt;    }&lt;br /&gt;    void printInt2(int i) {&lt;br /&gt;        QString name = sender()-&amp;gt;metaObject()-&amp;gt;className();&lt;br /&gt;        printf("Invoking printInt2(): %s.i=%d\n", qPrintable(name), i);&lt;br /&gt;    }&lt;br /&gt;    void printString1(QString str) {&lt;br /&gt;        QString name = sender()-&amp;gt;metaObject()-&amp;gt;className();&lt;br /&gt;        printf("Invoking printString1(): %s.str=%s\n", qPrintable(name), qPrintable(str));&lt;br /&gt;    }&lt;br /&gt;    void printString2(QString str) {&lt;br /&gt;        QString name = sender()-&amp;gt;metaObject()-&amp;gt;className();&lt;br /&gt;        printf("Invoking printString2(): %s.str=%s\n", qPrintable(name), qPrintable(str));&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif // MYTESTCLASS_H&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Test code:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;QtCore/QMetaClassInfo&amp;gt;&lt;br /&gt;#include &amp;lt;QtCore/QObject&amp;gt;&lt;br /&gt;#include &amp;lt;QtCore/QVariant&amp;gt;&lt;br /&gt;#include "qfakebase.h"&lt;br /&gt;#include "qfakederived.h"&lt;br /&gt;#include "mytestclass.h"&lt;br /&gt;&lt;br /&gt;using namespace Fake;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void myDumpClass(QMetaObject metaObject) {&lt;br /&gt;    printf("%s (\n", metaObject.className());&lt;br /&gt;    int start = metaObject.superClass()-&amp;gt;classInfoCount();&lt;br /&gt;    for (int i = start; i &amp;lt; metaObject.classInfoCount(); i++) {&lt;br /&gt;        printf("%s=\"%s\"\n",&lt;br /&gt;            metaObject.classInfo(i).name(), metaObject.classInfo(i).value());&lt;br /&gt;    }&lt;br /&gt;    printf(")\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;    /* Test class */&lt;br /&gt;    myDumpClass(QBase::staticMetaObject);&lt;br /&gt;    myDumpClass(QDerived::staticMetaObject);&lt;br /&gt;    /* Test property */&lt;br /&gt;    QBase base;&lt;br /&gt;    base.setId(111);&lt;br /&gt;    base.setProperty("name", QVariant("aaa"));&lt;br /&gt;    base.nonvirtualDump();&lt;br /&gt;    QDerived derived;&lt;br /&gt;    derived.setId(222);&lt;br /&gt;    derived.setAge(333);&lt;br /&gt;    derived.setProperty("name", QVariant("bbb"));&lt;br /&gt;    derived.setProperty("hash", QVariant("ccc"));&lt;br /&gt;    derived.nonvirtualDump();&lt;br /&gt;    /* Test polymorphism */&lt;br /&gt;    QBase *objs[2] = { &amp;amp;base, &amp;amp;derived };&lt;br /&gt;    for (int i = 0; i &amp;lt; 2; i++) {&lt;br /&gt;        objs[i]-&amp;gt;virtualDump();&lt;br /&gt;    }&lt;br /&gt;    /* Test signal/slot */&lt;br /&gt;    /* 1 &amp;lt;-&amp;gt; 1 */&lt;br /&gt;    MyTestClass instance;&lt;br /&gt;    QObject::connect(&amp;amp;base, &lt;br /&gt;        SIGNAL(basePrintInt(int)), &amp;amp;instance, SLOT(printInt1(int)));&lt;br /&gt;    QObject::connect(&amp;amp;base, &lt;br /&gt;        SIGNAL(basePrintString(QString)), &amp;amp;instance, SLOT(printString1(QString)));&lt;br /&gt;    base.emitBasePrintInt(12345);&lt;br /&gt;    base.emitBasePrintString("abcde");&lt;br /&gt;    /* 1 &amp;lt;-&amp;gt; 1+ */&lt;br /&gt;    QObject::connect(&amp;amp;base, &lt;br /&gt;        SIGNAL(basePrintInt(int)), &amp;amp;instance, SLOT(printInt2(int)));&lt;br /&gt;    base.emitBasePrintInt(123456);&lt;br /&gt;    /* signal inheritance */&lt;br /&gt;    QObject::connect(&amp;amp;derived, &lt;br /&gt;        SIGNAL(basePrintInt(int)), &amp;amp;instance, SLOT(printInt1(int)));&lt;br /&gt;    QObject::connect(&amp;amp;derived, &lt;br /&gt;        SIGNAL(basePrintString(QString)), &amp;amp;instance, SLOT(printString1(QString)));&lt;br /&gt;    QObject::connect(&amp;amp;derived, &lt;br /&gt;        SIGNAL(derivedPrintInt(int)), &amp;amp;instance, SLOT(printInt2(int)));&lt;br /&gt;    QObject::connect(&amp;amp;derived, &lt;br /&gt;        SIGNAL(derivedPrintString(QString)), &amp;amp;instance, SLOT(printString2(QString)));&lt;br /&gt;    derived.emitBasePrintInt(1234567);&lt;br /&gt;    derived.emitBasePrintString("abcdefg");&lt;br /&gt;    derived.emitDerivedPrintInt(1234567);&lt;br /&gt;    derived.emitDerivedPrintString("abcdefg");&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestQObject-{date}.zip file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-7910918943740188319?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/7910918943740188319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=7910918943740188319&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7910918943740188319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7910918943740188319'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oo-impelementation-in-c.html' title='OO Impelementation in C++'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-4985683327324423995</id><published>2011-03-12T18:20:00.002+08:00</published><updated>2011-03-15T16:43:14.086+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (9) - A Dynamic Type</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Recall there are 3 types in GObject type system: Fundamental, static and dynamic. A fundamental type is a top-most type which has no parent type. Most of them are pre-defined. Static types never load/unload its class type (say, their class struct) at runtime, since they are static. On the contrary, dynamic types can be dynamically loaded/unloaded at runtime. They are normally used within a module. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; We can call &lt;code&gt;g_type_register_dynamic()&lt;/code&gt; to register a dynamic type. When used in a module of GObject library (may be a &lt;code&gt;GTypeModule&lt;/code&gt; type), We can also call &lt;code&gt;g_type_module_register_type()&lt;/code&gt; to create your dynamic types. &lt;code&gt;g_type_register_dynamic()&lt;/code&gt; is invoked for you in that function. Let's go through the code:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;// bartype.h&lt;br /&gt;#ifndef BAR_TYPE_H_&lt;br /&gt;#define BAR_TYPE_H_&lt;br /&gt;&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* Bar type class struct */&lt;br /&gt;typedef struct _BarTypeClass {&lt;br /&gt;    GObjectClass parent;&lt;br /&gt;} BarTypeClass;&lt;br /&gt;&lt;br /&gt;/* Far type object struct */&lt;br /&gt;typedef struct _BarType {&lt;br /&gt;    GObject parent;&lt;br /&gt;} BarType;&lt;br /&gt;&lt;br /&gt;/* type function */&lt;br /&gt;GType bar_type_get_type();&lt;br /&gt;&lt;br /&gt;/* register type */&lt;br /&gt;void bar_type_register_type(GTypeModule *type_module);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* BAR_TYPE_H_ */&lt;/pre&gt;&lt;pre class="brush: c"&gt;// bartype.c&lt;br /&gt;#include "bartype.h"&lt;br /&gt;&lt;br /&gt;static gpointer parent_klass = NULL;&lt;br /&gt;static GType bar_type_type_id = 0;&lt;br /&gt;&lt;br /&gt;static void bar_type_instance_init(BarType *self) {&lt;br /&gt;    g_print("Calling bar_type_instance_init()\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void bar_type_instance_finalize(GObject *object) {&lt;br /&gt;    /* do some finalize, maybe release some dynamically allocated memory */&lt;br /&gt;    g_print("Calling bar_type_instance_finalize()\n");&lt;br /&gt;    /* chain to parent's finalize */&lt;br /&gt;    G_OBJECT_CLASS(parent_klass)-&amp;gt;finalize(object);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void bar_type_class_init(BarTypeClass *klass) {&lt;br /&gt;    g_print("Calling bar_type_class_init()\n");&lt;br /&gt;    parent_klass = g_type_class_peek_parent(klass);&lt;br /&gt;    G_OBJECT_CLASS(klass)-&amp;gt;finalize = bar_type_instance_finalize;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void bar_type_class_finalize(BarTypeClass *klass) {&lt;br /&gt;    g_print("Calling bar_type_class_finalize()\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GType bar_type_get_type() {&lt;br /&gt;    return bar_type_type_id;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void bar_type_register_type(GTypeModule *type_module) {&lt;br /&gt;    const GTypeInfo type_info = {&lt;br /&gt;        sizeof(BarTypeClass), /* class_size */&lt;br /&gt;        NULL,                   /* base_init */&lt;br /&gt;        NULL,                   /* base_finalize */&lt;br /&gt;        (GClassInitFunc)bar_type_class_init, /* class_init */&lt;br /&gt;        (GClassFinalizeFunc)bar_type_class_finalize, /* class_finalize */&lt;br /&gt;        NULL,                   /* class_data */&lt;br /&gt;        sizeof(BarType),        /* instance_size */&lt;br /&gt;        0,                      /* n_preallocs */&lt;br /&gt;        (GInstanceInitFunc)bar_type_instance_init, /* instance_init */&lt;br /&gt;        NULL                    /* value_table */&lt;br /&gt;    };&lt;br /&gt;    bar_type_type_id = g_type_module_register_type(&lt;br /&gt;        type_module, G_TYPE_OBJECT, "BarTypeDynamicClass", &amp;amp;type_info, 0);&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The implementation structure may be a little different with the stuff when creating a static type. An additional parameter &lt;code&gt;GTypeModule&lt;/code&gt; is passed in. It represents the module your dynamic type belongs to. So, when the module is unloaded, all dynamic types in it are unaccessible. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Also note the &lt;code&gt;bar_type_class_finalize()&lt;/code&gt; function. We use it to override the &lt;code&gt;finalize()&lt;/code&gt; virtual function in &lt;code&gt;GObjectClass&lt;/code&gt;. Now you can do un-initialiation in this function. It is like the destructor in a C++ class. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Let's move on to the module type. This type inherits &lt;code&gt;GTypeModule&lt;/code&gt;:&lt;br /&gt;&lt;pre class="brush: c"&gt;// fakemodule.h&lt;br /&gt;#ifndef FAKE_MODULE_H_&lt;br /&gt;#define FAKE_MODULE_H_&lt;br /&gt;&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* module object struct */&lt;br /&gt;typedef struct _FakeModule {&lt;br /&gt;    GTypeModule parent;&lt;br /&gt;} FakeModule;&lt;br /&gt;&lt;br /&gt;/* module class struct */&lt;br /&gt;typedef struct _FakeModuleClass {&lt;br /&gt;    GTypeModuleClass parent;&lt;br /&gt;} FakeModuleClass;&lt;br /&gt;&lt;br /&gt;/* type method */&lt;br /&gt;GType fake_module_get_type();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* FAKE_MODULE_H_ */&lt;/pre&gt;&lt;pre class="brush: c"&gt;// fakemodule.c&lt;br /&gt;#include "fakemodule.h"&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * If you implement a real shared library module, you&lt;br /&gt; * can init module variables, assign virtual function here.&lt;br /&gt; */&lt;br /&gt;gboolean fake_module_load(GTypeModule *module) {&lt;br /&gt;    g_print("Invoking fake_module_load()\n");&lt;br /&gt;    /* successfully loaded */&lt;br /&gt;    return TRUE;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * If you implement a real shared library module, you&lt;br /&gt; * can uninit module variables, and make all cleanups here.&lt;br /&gt; */&lt;br /&gt;void fake_module_unload(GTypeModule *module) {&lt;br /&gt;    /* noop */&lt;br /&gt;    g_print("Invoking fake_module_unload()\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_module_class_init(FakeModuleClass *klass, gpointer data) {&lt;br /&gt;    g_print("Calling fake_module_class_init()\n");&lt;br /&gt;    GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS(klass);&lt;br /&gt;    module_class-&amp;gt;load = fake_module_load;&lt;br /&gt;    module_class-&amp;gt;unload = fake_module_unload;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_module_instance_init(FakeModule *instance, gpointer data) {&lt;br /&gt;    g_print("Calling fake_module_instance_init()\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GType fake_module_get_type() {&lt;br /&gt;    static GType type_id = 0;&lt;br /&gt;    if (type_id == 0) {&lt;br /&gt;        static const GTypeInfo type_info = {&lt;br /&gt;            sizeof(FakeModuleClass), /* class_size */&lt;br /&gt;            NULL,                   /* base_init */&lt;br /&gt;            NULL,                   /* base_finalize */&lt;br /&gt;            (GClassInitFunc)fake_module_class_init, /* class_init */&lt;br /&gt;            NULL,                   /* class_finalize */&lt;br /&gt;            NULL,                   /* class_data */&lt;br /&gt;            sizeof(FakeModule),     /* instance_size */&lt;br /&gt;            0,                      /* n_preallocs */&lt;br /&gt;            (GInstanceInitFunc)fake_module_instance_init, /* instance_init */&lt;br /&gt;            NULL                    /* value_table */&lt;br /&gt;        };&lt;br /&gt;        type_id = g_type_register_static(&lt;br /&gt;            G_TYPE_TYPE_MODULE, "FakeModuleStaticClass", &amp;amp;type_info, 0);&lt;br /&gt;    }&lt;br /&gt;    return type_id;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;GTypeModule&lt;/code&gt; is an abstract type. We should implements its &lt;code&gt;load()&lt;/code&gt; and &lt;code&gt;unload()&lt;/code&gt; virtual function.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Our test code:&lt;br /&gt;&lt;pre class="brush: c"&gt;// main.c&lt;br /&gt;#include "footype.h"&lt;br /&gt;#include "bartype.h"&lt;br /&gt;#include "fakemodule.h"&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * Module entry point. If you implement a real shared library module,&lt;br /&gt; * you can use dlopen()/dlsym() or g_module_open()/g_module_symbol() to&lt;br /&gt; * load this module dynamically.&lt;br /&gt; */&lt;br /&gt;void module_init(GTypeModule *type_module) {&lt;br /&gt;    foo_type_register_type(type_module);&lt;br /&gt;    bar_type_register_type(type_module);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;    g_type_init();&lt;br /&gt;&lt;br /&gt;    FakeModule *module = (FakeModule *)g_object_new(fake_module_get_type(), NULL);&lt;br /&gt;    module_init((GTypeModule *)module);&lt;br /&gt;&lt;br /&gt;    /*&lt;br /&gt;     * Add a reference to foo type class here. Otherwise, the fake module&lt;br /&gt;     * will be unloaded right after the free() of foo type object and cause error.&lt;br /&gt;     */&lt;br /&gt;    FooTypeClass *foo_type_class = (FooTypeClass *)g_type_class_ref(foo_type_get_type());&lt;br /&gt;&lt;br /&gt;    FooType *foo_type = (FooType *)g_object_new(foo_type_get_type(), NULL);&lt;br /&gt;    BarType *bar_type = (BarType *)g_object_new(bar_type_get_type(), NULL);&lt;br /&gt;&lt;br /&gt;    /* Test for override finalize() */&lt;br /&gt;    g_object_unref(foo_type);&lt;br /&gt;    g_object_unref(bar_type);&lt;br /&gt;&lt;br /&gt;    g_type_class_unref(foo_type_class);&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Another dynamic type &lt;code&gt;BarType&lt;/code&gt; is defined in addition to &lt;code&gt;FooType&lt;/code&gt; to demo the usage. The output maybe:&lt;br /&gt;&lt;pre class="brush: plain"&gt;Calling fake_module_class_init()&lt;br /&gt;Calling fake_module_instance_init()&lt;br /&gt;Invoking fake_module_load()&lt;br /&gt;Calling foo_type_class_init()&lt;br /&gt;Calling foo_type_instance_init()&lt;br /&gt;Calling bar_type_class_init()&lt;br /&gt;Calling bar_type_instance_init()&lt;br /&gt;Calling foo_type_instance_finalize()&lt;br /&gt;Calling bar_type_instance_finalize()&lt;br /&gt;Calling bar_type_class_finalize()&lt;br /&gt;Calling foo_type_class_finalize()&lt;br /&gt;Invoking fake_module_unload()&lt;br /&gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; See the init/finalize process? &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; At the end of my note, Let me summarize to compare GObject library with C++ implementation:&lt;br /&gt;1. Member Variables:&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="text-align: center; width: 500px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GObject&lt;/td&gt;&lt;td&gt;C++&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;in class struct&lt;/td&gt;&lt;td&gt;class meta info&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;in object struct&lt;/td&gt;&lt;td&gt;class instance member&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;global variable&lt;/td&gt;&lt;td&gt;class static member&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;2. Function Callbacks:&lt;br /&gt;&lt;table border="1" cellpadding="0" cellspacing="0" style="text-align: center; width: 700px;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="width: 200px;"&gt;GObject&lt;/td&gt;&lt;td&gt;C++&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;base_init&lt;/td&gt;&lt;td&gt;init class dynamic meta info&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;base_finalize&lt;/td&gt;&lt;td&gt;finalize dynamic class meta info, only dynamic types use it&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;class_init&lt;/td&gt;&lt;td&gt;init class static meta info&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;class_finalize&lt;/td&gt;&lt;td&gt;finalize class static meta info, only dynamic types use it&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;instance_init&lt;/td&gt;&lt;td&gt;init instace, like C++ constructor&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;override finalize in GObjectClass&lt;/td&gt;&lt;td&gt;finalize instance, like C++ destructor&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject7 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-4985683327324423995?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/4985683327324423995/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=4985683327324423995&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4985683327324423995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4985683327324423995'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-9-dynamic-type.html' title='OOP Using GObject (9) - A Dynamic Type'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1766172840444715669</id><published>2011-03-12T02:29:00.002+08:00</published><updated>2011-03-15T16:43:33.954+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (8) - An interface</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Interfaces usage in library is like class usage. We need to define a interface struct, but no object struct is needed:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;typedef struct _FakeIServer FakeIServer; /* dummy object */&lt;br /&gt;typedef struct _FakeIServerInterface {&lt;br /&gt;    GTypeInterface parent;&lt;br /&gt;    void (*response)(FakeIServer *instance);&lt;br /&gt;} FakeIServerInterface;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then we register the interface using &lt;code&gt;g_type_register_static()&lt;/code&gt; with &lt;code&gt;G_TYPE_INTERFACE&lt;/code&gt; as first parameter. For interfaces, we only need to assign &lt;code&gt;base_init()&lt;/code&gt; and &lt;code&gt;base_finalize()&lt;/code&gt;callbacks.&lt;br /&gt;&lt;pre class="brush: c"&gt;static void fake_iserver_base_init(gpointer g_class) {&lt;br /&gt;    static gboolean is_initialized = FALSE;&lt;br /&gt;    if (!is_initialized) {&lt;br /&gt;        /* add properties and signals to the interface here */&lt;br /&gt;        is_initialized = TRUE;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GType fake_iserver_get_type() {&lt;br /&gt;    static GType type_id = 0;&lt;br /&gt;    if (type_id == 0) {&lt;br /&gt;        static const GTypeInfo interface_info = {&lt;br /&gt;            sizeof(FakeIServerInterface),   /* class_size */&lt;br /&gt;            fake_iserver_base_init,         /* base_init */&lt;br /&gt;            NULL,                           /* base_finalize */&lt;br /&gt;        };&lt;br /&gt;        type_id = g_type_register_static(&lt;br /&gt;            G_TYPE_INTERFACE, "FakeIServerInterface", &amp;amp;interface_info, 0);&lt;br /&gt;    }&lt;br /&gt;    return type_id;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; As described in the &lt;a href="http://library.gnome.org/devel/gobject/stable/gobject-Type-Information.html#GClassInitFunc"&gt;official document&lt;/a&gt;, we should allocate dynamic memebers of class struct in&lt;code&gt;base_init()&lt;/code&gt;. Otherwise, all copies of the class struct share only one copy of dynamic members. This leads to problems. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Let's define the type which implements the interface:&lt;br /&gt;&lt;pre class="brush: c"&gt;// fakedesktop.h&lt;br /&gt;#ifndef FAKE_DESKTOP_H_&lt;br /&gt;#define FAKE_DESKTOP_H_&lt;br /&gt;&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define FAKE_TYPE_DESKTOP              ( fake_desktop_get_type() )&lt;br /&gt;#define FAKE_DESKTOP(obj)              \&lt;br /&gt; ( G_TYPE_CHECK_INSTANCE_CAST((obj), FAKE_TYPE_DESKTOP, FakeDesktop) )&lt;br /&gt;#define FAKE_IS_DESKTOP(obj)           \&lt;br /&gt; ( G_TYPE_CHECK_INSTANCE_TYPE((obj), FAKE_TYPE_DESKTOP) )&lt;br /&gt;#define FAKE_DESKTOP_CLASS(cls)        \&lt;br /&gt; ( G_TYPE_CHECK_CLASS_CAST((cls), FAKE_TYPE_DESKTOP, FakeDesktopClass) )&lt;br /&gt;#define FAKE_IS_DESKTOP_CLASS(cls)     \&lt;br /&gt; ( G_TYPE_CHECK_CLASS_TYPE((cls), FAKE_TYPE_DESKTOP) )&lt;br /&gt;#define FAKE_DESKTOP_GET_CLASS(obj)    \&lt;br /&gt; ( G_TYPE_INSTANCE_GET_CLASS((obj), FAKE_TYPE_DESKTOP, FakeDesktopClass ) )&lt;br /&gt;&lt;br /&gt;/* Base object struct */&lt;br /&gt;typedef struct _FakeDesktop {&lt;br /&gt;    /* GObject as the first field */&lt;br /&gt;    GObject parent;&lt;br /&gt;} FakeDesktop;&lt;br /&gt;&lt;br /&gt;/* Base class struct */&lt;br /&gt;typedef struct _FakeDesktopClass {&lt;br /&gt;    /* GObjectClass as the first field */&lt;br /&gt;    GObjectClass parent;&lt;br /&gt;} FakeDesktopClass;&lt;br /&gt;&lt;br /&gt;/* type method */&lt;br /&gt;GType fake_desktop_get_type();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* FAKE_DESKTOP_H_ */&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Note the naming convention I used here. Our &lt;code&gt;FakeDesktop&lt;/code&gt; class will implement the &lt;code&gt;FakeIServer&lt;/code&gt; interface and another &lt;code&gt;FakeIClient&lt;/code&gt; interface. This time do not use corresponding interface struct as the first members of &lt;code&gt;FakeDesktop&lt;/code&gt; and &lt;code&gt;FakeDesktopClass&lt;/code&gt;. Interface info will be added dynamically when initialize a real instance of &lt;code&gt;FakeDesktop&lt;/code&gt;. Let's move to the *.c code:&lt;br /&gt;&lt;pre class="brush: c"&gt;// fakedesktop.c&lt;br /&gt;#include "fakedesktop.h"&lt;br /&gt;#include "fakeiface.h"&lt;br /&gt;&lt;br /&gt;void fake_desktop_request(FakeIClient *instance) {&lt;br /&gt;    g_print("Invoking fake_desktop_request()\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void fake_desktop_response(FakeIServer *instance) {&lt;br /&gt;    g_print("Invoking fake_desktop_response()\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_desktop_class_init(FakeDesktopClass *klass, gpointer data) {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_desktop_instance_init(FakeDesktop *instance, gpointer data) {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_desktop_interface_init_iclient(FakeIClientInterface* iface, gpointer iface_data) {&lt;br /&gt;    iface-&gt;request = fake_desktop_request;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_desktop_interface_init_iserver(FakeIServerInterface* iface, gpointer iface_data) {&lt;br /&gt;    iface-&gt;response = fake_desktop_response;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GType fake_desktop_get_type() {&lt;br /&gt;    static GType type_id = 0;&lt;br /&gt;    if (type_id == 0) {&lt;br /&gt;        static const GTypeInfo type_info = {&lt;br /&gt;            sizeof(FakeDesktopClass),  /* class_size */&lt;br /&gt;            NULL,                   /* base_init */&lt;br /&gt;            NULL,                   /* base_finalize */&lt;br /&gt;            (GClassInitFunc)fake_desktop_class_init, /* class_init */&lt;br /&gt;            NULL,                   /* class_finalize */&lt;br /&gt;            NULL,                   /* class_data */&lt;br /&gt;            sizeof(FakeDesktop),    /* instance_size */&lt;br /&gt;            0,                      /* n_preallocs */&lt;br /&gt;            (GInstanceInitFunc)fake_desktop_instance_init, /* instance_init */&lt;br /&gt;            NULL                    /* value_table */&lt;br /&gt;        };&lt;br /&gt;        type_id = g_type_register_static(G_TYPE_OBJECT, "FakeDesktopClass", &amp;type_info, 0);&lt;br /&gt;&lt;br /&gt;        /* add interface */&lt;br /&gt;        GInterfaceInfo interface_info_iclient = {&lt;br /&gt;            (GInterfaceInitFunc)fake_desktop_interface_init_iclient, /* interface_init */&lt;br /&gt;            NULL,   /* interface_finalize */&lt;br /&gt;            NULL,   /* interface_data */&lt;br /&gt;        };&lt;br /&gt;        GInterfaceInfo interface_info_iserver = {&lt;br /&gt;            (GInterfaceInitFunc)fake_desktop_interface_init_iserver, /* interface_init */&lt;br /&gt;            NULL,   /* interface_finalize */&lt;br /&gt;            NULL,   /* interface_data */&lt;br /&gt;        };&lt;br /&gt;        g_type_add_interface_static(type_id, FAKE_TYPE_ICLIENT, &amp;interface_info_iclient);&lt;br /&gt;        g_type_add_interface_static(type_id, FAKE_TYPE_ISERVER, &amp;interface_info_iserver);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return type_id;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Note the &lt;code&gt;g_type_add_interface_static()&lt;/code&gt; function call to add interface info. The interface info is defined in a &lt;code&gt;GInterfaceInfo&lt;/code&gt; struct. We just make use of the &lt;code&gt;interface_init()&lt;/code&gt; callback. In it, we assign function pointers of corresponding interface to our implementation function. We can add multiple interface infos to implement them.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Finally, the test code:&lt;br /&gt;&lt;pre class="brush: c"&gt;// main.c&lt;br /&gt;#include "fakeiface.h"&lt;br /&gt;#include "fakedesktop.h"&lt;br /&gt;#include "fakelaptop.h"&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;void my_dump_type(GType type_id) {&lt;br /&gt;    g_print("Type id: %d\n", type_id);&lt;br /&gt;    g_print("Type name: %s\n", g_type_name(type_id));&lt;br /&gt;    g_print("Is fundamental? %s\n", G_TYPE_IS_FUNDAMENTAL(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is derived? %s\n", G_TYPE_IS_DERIVED(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is interface? %s\n", G_TYPE_IS_INTERFACE(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is classed? %s\n", G_TYPE_IS_CLASSED(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is instantiatable? %s\n", G_TYPE_IS_INSTANTIATABLE(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is derivable? %s\n", G_TYPE_IS_DERIVABLE(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is deep derivable? %s\n", G_TYPE_IS_DEEP_DERIVABLE(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is abstract? %s\n", G_TYPE_IS_ABSTRACT(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is value abstract? %s\n", G_TYPE_IS_VALUE_ABSTRACT(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Is value type: %s\n", G_TYPE_IS_VALUE_TYPE(type_id) ? "yes" : "no");&lt;br /&gt;    g_print("Has value table: %s\n", G_TYPE_HAS_VALUE_TABLE(type_id) ? "yes" : "no");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;    g_type_init();&lt;br /&gt;    my_dump_type(FAKE_TYPE_ICLIENT);&lt;br /&gt;    my_dump_type(FAKE_TYPE_ISERVER);&lt;br /&gt;    my_dump_type(FAKE_TYPE_LAPTOP);&lt;br /&gt;    my_dump_type(FAKE_TYPE_DESKTOP);&lt;br /&gt;&lt;br /&gt;    FakeLaptop *laptop = (FakeLaptop *)g_object_new(FAKE_TYPE_LAPTOP, NULL);&lt;br /&gt;    FakeDesktop *desktop = (FakeDesktop *)g_object_new(FAKE_TYPE_DESKTOP, NULL);&lt;br /&gt;    g_print("laptop is FakeIServer? %s\n", FAKE_IS_ISERVER(laptop) ? "yes" : "no");&lt;br /&gt;    g_print("laptop is FakeIClient? %s\n", FAKE_IS_ICLIENT(laptop) ? "yes" : "no");&lt;br /&gt;    g_print("desktop is FakeIServer? %s\n", FAKE_IS_ISERVER(desktop) ? "yes" : "no");&lt;br /&gt;    g_print("desktop is FakeIClient? %s\n", FAKE_IS_ICLIENT(desktop) ? "yes" : "no");&lt;br /&gt;&lt;br /&gt;    /* Polynophysm */&lt;br /&gt;    int i;&lt;br /&gt;    FakeIServer *servers[2] = { (FakeIServer *)laptop, (FakeIServer *)desktop };&lt;br /&gt;    for (i = 0; i &lt; 2; i++) {&lt;br /&gt;        FakeIServer *inst = servers[i];&lt;br /&gt;        FakeIServerInterface *iface = FAKE_ISERVER_GET_INTERFACE(inst);&lt;br /&gt;        if (iface) {&lt;br /&gt;            iface-&gt;response(inst);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    FakeIClient *clients[2] = { (FakeIClient *)laptop, (FakeIClient *)desktop };&lt;br /&gt;    for (i = 0; i &lt; 2; i++) {&lt;br /&gt;        FakeIClient *inst = clients[i];&lt;br /&gt;        FakeIClientInterface *iface = FAKE_ICLIENT_GET_INTERFACE(inst);&lt;br /&gt;        if (iface) {&lt;br /&gt;            iface-&gt;request(inst);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In runtime, if your classed type implements an interface, it will be considered as the interface type (is-a).&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject6 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1766172840444715669?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1766172840444715669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1766172840444715669&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1766172840444715669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1766172840444715669'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-8-interface.html' title='OOP Using GObject (8) - An interface'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-7669121850385522451</id><published>2011-03-11T22:36:00.002+08:00</published><updated>2011-03-15T16:43:39.728+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (7) - Signals</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Signals in GObject are used to support a event-driven programming. Signals can be connected to callback handlers. When they are emitted, these handlers are invoked. To add signals to a type, notice following lines of code:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;pre class="brush: c"&gt;static void fake_base_class_init(FakeBaseClass *klass, gpointer data) {&lt;br /&gt;    // ...&lt;br /&gt;    /* signals */&lt;br /&gt;    g_signal_new("base-signal-int", FAKE_TYPE_BASE, G_SIGNAL_RUN_LAST, 0,&lt;br /&gt;        NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT, NULL);&lt;br /&gt;    g_signal_new("base-signal-string", FAKE_TYPE_BASE, G_SIGNAL_RUN_LAST, 0,&lt;br /&gt;        NULL, NULL, g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING, NULL);&lt;br /&gt;    // ...&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Like properties, signals can be inherited too. Use signals like:&lt;br /&gt;&lt;pre class="brush: c"&gt;int main() {&lt;br /&gt;    // ...&lt;br /&gt;    FakeBase *base = (FakeBase *)g_object_new(FAKE_TYPE_BASE, NULL);&lt;br /&gt;    FakeDerived *derived = (FakeDerived *)g_object_new(FAKE_TYPE_DERIVED, NULL);&lt;br /&gt;    /* Test for signals */&lt;br /&gt;    /* 1 &lt;-&gt; 1 */&lt;br /&gt;    g_signal_connect(base, "base-signal-int", G_CALLBACK(print_int1), NULL);&lt;br /&gt;    g_signal_connect(base, "base-signal-string", G_CALLBACK(print_string1), NULL);&lt;br /&gt;    g_signal_emit_by_name(base, "base-signal-int", 12345);&lt;br /&gt;    g_signal_emit_by_name(base, "base-signal-string", "abcde");&lt;br /&gt;    /* 1 &lt;-&gt; 1+ */&lt;br /&gt;    g_signal_connect(base, "base-signal-int", G_CALLBACK(print_int2), NULL);&lt;br /&gt;    g_signal_emit_by_name(base, "base-signal-int", 123456);&lt;br /&gt;    /* signal inheritance */&lt;br /&gt;    g_signal_connect(derived, "base-signal-int", G_CALLBACK(print_int1), NULL);&lt;br /&gt;    g_signal_connect(derived, "base-signal-string", G_CALLBACK(print_string1), NULL);&lt;br /&gt;    g_signal_connect(derived, "derived-signal-int", G_CALLBACK(print_int2), NULL);&lt;br /&gt;    g_signal_connect(derived, "derived-signal-string", G_CALLBACK(print_string2), NULL);&lt;br /&gt;    g_signal_emit_by_name(derived, "base-signal-int", 1234567);&lt;br /&gt;    g_signal_emit_by_name(derived, "base-signal-string", "abcdefg");&lt;br /&gt;    g_signal_emit_by_name(derived, "derived-signal-int", 1234567);&lt;br /&gt;    g_signal_emit_by_name(derived, "derived-signal-string", "abcdefg");&lt;br /&gt;    // ...&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The callback functions are defined simply like:&lt;br /&gt;&lt;pre class="brush: c"&gt;void print_int1(GObject *sender, int i, gpointer data) {&lt;br /&gt;    if (FAKE_IS_DERIVED(sender)) {&lt;br /&gt;        g_print("Invoking print_int1(): derived.i=%d\n", i);&lt;br /&gt;    } else if (FAKE_IS_BASE(sender)) {&lt;br /&gt;        g_print("Invoking print_int1(): base.i=%d\n", i);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void print_int2(GObject *sender, int i, gpointer data) {&lt;br /&gt;    if (FAKE_IS_DERIVED(sender)) {&lt;br /&gt;        g_print("Invoking print_int2(): derived.i=%d\n", i);&lt;br /&gt;    } else if (FAKE_IS_BASE(sender)) {&lt;br /&gt;        g_print("Invoking print_int2(): base.i=%d\n", i);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void print_string1(GObject *sender, gchar* str, gpointer data) {&lt;br /&gt;    if (FAKE_IS_DERIVED(sender)) {&lt;br /&gt;        g_print("Invoking print_string1(): derived.str=\"%s\"\n", str);&lt;br /&gt;    } else if (FAKE_IS_BASE(sender)) {&lt;br /&gt;        g_print("Invoking print_string1(): base.str=\"%s\"\n", str);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void print_string2(GObject *sender, gchar* str, gpointer data) {&lt;br /&gt;    if (FAKE_IS_DERIVED(sender)) {&lt;br /&gt;        g_print("Invoking print_string2(): derived.str=\"%s\"\n", str);&lt;br /&gt;    } else if (FAKE_IS_BASE(sender)) {&lt;br /&gt;        g_print("Invoking print_string2(): base.str=\"%s\"\n", str);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject5 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-7669121850385522451?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/7669121850385522451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=7669121850385522451&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7669121850385522451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7669121850385522451'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-7-signals.html' title='OOP Using GObject (7) - Signals'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5313773126959428418</id><published>2011-03-11T22:19:00.004+08:00</published><updated>2011-03-15T17:07:13.003+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='Property'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (6) - Properties</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Properties are supported by the GObject library. To use it, you should override the &lt;code&gt;set_property()&lt;/code&gt; and &lt;code&gt;get_property()&lt;/code&gt; function in &lt;code&gt;GObjectClass&lt;/code&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;enum {&lt;br /&gt;    PROP_0,&lt;br /&gt;    PROP_BASE_ID,&lt;br /&gt;    PROP_BASE_NAME&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;static void fake_base_set_property(GObject *object,&lt;br /&gt;    guint property_id, const GValue *value, GParamSpec *pspec) {&lt;br /&gt;    FakeBase *self = FAKE_BASE(object);&lt;br /&gt;    switch (property_id) {&lt;br /&gt;        case PROP_BASE_ID:&lt;br /&gt;            self-&amp;gt;priv-&amp;gt;id = g_value_get_int(value);&lt;br /&gt;            break;&lt;br /&gt;        case PROP_BASE_NAME:&lt;br /&gt;            g_free(self-&amp;gt;priv-&amp;gt;name);&lt;br /&gt;            self-&amp;gt;priv-&amp;gt;name = g_value_dup_string(value);&lt;br /&gt;            break;&lt;br /&gt;        default:&lt;br /&gt;            /* We don't have any other property... */&lt;br /&gt;            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);&lt;br /&gt;            break;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_base_get_property(GObject *object,&lt;br /&gt;    guint property_id, GValue *value, GParamSpec *pspec) {&lt;br /&gt;    FakeBase *self = FAKE_BASE(object);&lt;br /&gt;    switch (property_id) {&lt;br /&gt;        case PROP_BASE_ID:&lt;br /&gt;            g_value_set_int(value, self-&amp;gt;priv-&amp;gt;id);&lt;br /&gt;            break;&lt;br /&gt;        case PROP_BASE_NAME:&lt;br /&gt;            g_value_set_string(value, self-&amp;gt;priv-&amp;gt;name);&lt;br /&gt;            break;&lt;br /&gt;        default:&lt;br /&gt;            /* We don't have any other property... */&lt;br /&gt;            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);&lt;br /&gt;            break;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_base_class_init(FakeBaseClass *klass, gpointer data) {&lt;br /&gt;    // ...&lt;br /&gt;    /* properties */&lt;br /&gt;    GObjectClass *gobject_klass = G_OBJECT_CLASS(klass);&lt;br /&gt;    gobject_klass-&amp;gt;set_property = fake_base_set_property;&lt;br /&gt;    gobject_klass-&amp;gt;get_property = fake_base_get_property;&lt;br /&gt;    GParamSpec *pspec;&lt;br /&gt;    pspec = g_param_spec_int("base-id", "Base ID", &lt;br /&gt;        "Set/Get Base ID", -1000, 1000, 0, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);&lt;br /&gt;    g_object_class_install_property(gobject_klass, PROP_BASE_ID, pspec);&lt;br /&gt;    pspec = g_param_spec_string("base-name",&lt;br /&gt;        "Base Name", "Set/Get Base Name ", NULL, G_PARAM_READWRITE);&lt;br /&gt;    g_object_class_install_property(gobject_klass, PROP_BASE_NAME, pspec);&lt;br /&gt;    // ...&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All APIs are clear and easy to use, please refer to the official document. Last but not least, properties can be inherited by derived classes. Here's my test code:&lt;pre class="brush: c"&gt;int main() {&lt;br /&gt;    // ...&lt;br /&gt;    /* Base object */&lt;br /&gt;    FakeBase *base = (FakeBase *)g_object_new(FAKE_TYPE_BASE, "base-id", 111, NULL);&lt;br /&gt;    GValue base_name = { 0 };&lt;br /&gt;    g_value_init(&amp;base_name, G_TYPE_STRING);&lt;br /&gt;    g_value_set_static_string(&amp;base_name, "aaa");&lt;br /&gt;    g_object_set_property(G_OBJECT(base), "base-name", &amp;base_name);&lt;br /&gt;    g_value_unset(&amp;base_name);&lt;br /&gt;    /* Derived object */&lt;br /&gt;    FakeDerived *derived = (FakeDerived *)g_object_new(&lt;br /&gt;        FAKE_TYPE_DERIVED, "base-id", 222, "derived-age", 333, NULL);&lt;br /&gt;    g_object_set(derived, "base-name", "bbb", "derived-hash", "ccc", NULL);&lt;br /&gt;    // ...&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; As you see, we can get/set properties one by one or using a parameter list.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject5 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5313773126959428418?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5313773126959428418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5313773126959428418&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5313773126959428418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5313773126959428418'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-6-properties.html' title='OOP Using GObject (6) - Properties'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-33078012367662812</id><published>2011-03-11T17:39:00.004+08:00</published><updated>2011-03-15T16:44:07.696+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (5) - Private Members</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Here's some trivial note on using GObject library.&lt;br /&gt;1. Private members:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Recall our definition of &lt;code&gt;Base&lt;/code&gt; type:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;/* Base object struct */&lt;br /&gt;typedef struct _Base {&lt;br /&gt;    GTypeInstance parent;&lt;br /&gt;    /* instance variable, should be hidden */&lt;br /&gt;    gint base_instance_i;&lt;br /&gt;} Base;&lt;br /&gt;&lt;br /&gt;/* Base class struct */&lt;br /&gt;typedef struct _BaseClass {&lt;br /&gt;    GTypeClass parent;&lt;br /&gt;    /* instance method, used as a virtual method */&lt;br /&gt;    void (*base_instance_dump)(struct _Base *instance);&lt;br /&gt;} BaseClass;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; It expose the visibility of &lt;code&gt;base_instance_i&lt;/code&gt; field. We should keep encapsulation in OOP. GObject library has support for this. We can define the class as:&lt;br /&gt;&lt;pre class="brush: c"&gt;/* private data of Base object */&lt;br /&gt;typedef struct _FakeBasePrivate FakeBasePrivate;&lt;br /&gt;&lt;br /&gt;/* Base object struct */&lt;br /&gt;typedef struct _FakeBase {&lt;br /&gt;    /* GObject as the first field */&lt;br /&gt;    GObject parent;&lt;br /&gt;    /* private data */&lt;br /&gt;    FakeBasePrivate *priv;&lt;br /&gt;} FakeBase;&lt;br /&gt;&lt;br /&gt;/* Base class struct */&lt;br /&gt;typedef struct _FakeBaseClass {&lt;br /&gt;    /*&lt;br /&gt;     * The type GObject is supposed to be the base class of other user-defined classes.&lt;br /&gt;     *   - Reference count support.&lt;br /&gt;     *   - Support adding properties to GObject subclasses.&lt;br /&gt;     *   - Support signals for asynchronized event handling like "event" in C#.&lt;br /&gt;     */&lt;br /&gt;    /* GObjectClass as the first field */&lt;br /&gt;    GObjectClass parent;&lt;br /&gt;    /*&lt;br /&gt;     * Since glib 2.24, there're new functions to keep privacy:&lt;br /&gt;     *   - g_type_add_class_private()&lt;br /&gt;     *   - g_type_class_get_private()&lt;br /&gt;     */&lt;br /&gt;    /* private static field */&lt;br /&gt;    gint version;&lt;br /&gt;    /* private dynamic field */&lt;br /&gt;    gchar *author;&lt;br /&gt;    /* instance method, used as a virtual method */&lt;br /&gt;    void (*virtual_dump)(struct _FakeBase *instance);&lt;br /&gt;} FakeBaseClass;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; We declare a new &lt;code&gt;FakeBasePrivate&lt;/code&gt; struct to contain all private field used in &lt;code&gt;FakeBase&lt;/code&gt; type. And the private struct is defined in *.c file, so its internal representation remains invisible. Then in *.c file, we got:&lt;br /&gt;&lt;pre class="brush: c"&gt;struct _FakeBasePrivate {&lt;br /&gt;    gint id;&lt;br /&gt;    gchar *name;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;static void fake_base_class_init(FakeBaseClass *klass, gpointer data) {&lt;br /&gt;    // ...&lt;br /&gt;    /* Registers a private structure for an instantiable type. */&lt;br /&gt;    g_type_class_add_private(klass, sizeof(FakeBasePrivate));&lt;br /&gt;    // ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void fake_base_instance_init(FakeBase *instance, gpointer data) {&lt;br /&gt;    // ...&lt;br /&gt;    instance-&amp;gt;priv = &lt;br /&gt;        G_TYPE_INSTANCE_GET_PRIVATE(instance, FAKE_TYPE_BASE, FakeBasePrivate);&lt;br /&gt;    // ...&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The private member is malloc in &lt;code&gt;class_init()&lt;/code&gt; callback, and is ready to use after invoking &lt;code&gt;instance_init()&lt;/code&gt;. When we will use property mechanism to get/set these private field later.&lt;br /&gt;&lt;br /&gt;2. Naming convention:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Official document: &lt;a href="http://library.gnome.org/devel/gobject/stable/gtype-conventions.html"&gt;http://library.gnome.org/devel/gobject/stable/gtype-conventions.html&lt;/a&gt;. Just follow it to make your code more readable. &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject5 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-33078012367662812?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/33078012367662812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=33078012367662812&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/33078012367662812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/33078012367662812'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-5-private-members.html' title='OOP Using GObject (5) - Private Members'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-7785509627315629305</id><published>2011-03-11T17:06:00.003+08:00</published><updated>2011-03-15T16:44:20.067+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (4) - An Inheritable Class</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Now, we will begin to implement some real OO mechanism using GObject library. In this article, we will make our fundamental type Inheritable. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Here's comes our Base type:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;// base.h&lt;br /&gt;#ifndef BASE_H_&lt;br /&gt;#define BASE_H_&lt;br /&gt;&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* Base object struct */&lt;br /&gt;typedef struct _Base {&lt;br /&gt;    GTypeInstance parent;&lt;br /&gt;    /* instance variable, should be hidden */&lt;br /&gt;    gint base_instance_i;&lt;br /&gt;} Base;&lt;br /&gt;&lt;br /&gt;/* Base class struct */&lt;br /&gt;typedef struct _BaseClass {&lt;br /&gt;    GTypeClass parent;&lt;br /&gt;    /* instance method, used as a virtual method */&lt;br /&gt;    void (*base_instance_dump)(struct _Base *instance);&lt;br /&gt;} BaseClass;&lt;br /&gt;&lt;br /&gt;/* static method of Base class */&lt;br /&gt;void base_class_set_i(gint i);&lt;br /&gt;&lt;br /&gt;/* non-virtual public method for Base object */&lt;br /&gt;void base_instance_set_i(Base *instance, gint i);&lt;br /&gt;&lt;br /&gt;/* virtual public method for Base object, both version are supported */&lt;br /&gt;void base_instance_dump(Base *instance);&lt;br /&gt;&lt;br /&gt;/* type method */&lt;br /&gt;GType base_get_type();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* BASE_H_ */&lt;/pre&gt;&lt;pre class="brush: c"&gt;// base.c&lt;br /&gt;#include "base.h"&lt;br /&gt;&lt;br /&gt;/* static field of Base class */&lt;br /&gt;gint base_class_i;&lt;br /&gt;&lt;br /&gt;/* static method of Base class */&lt;br /&gt;void base_class_set_i(gint i) {&lt;br /&gt;    base_class_i = i;&lt;br /&gt;    g_print("Invoking base_class_set_i(): base_class_i=%d\n", base_class_i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void base_instance_set_i(Base *instance, gint i) {&lt;br /&gt;    instance-&gt;base_instance_i = i;&lt;br /&gt;    g_print("Invoking base_instance_set_i(): base_instance_i=%d\n", instance-&gt;base_instance_i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void base_instance_dump(Base *instance) {&lt;br /&gt;    g_print("Invoking base_instance_dump(): base_instance_i=%d\n", instance-&gt;base_instance_i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void base_class_init(BaseClass *klass, gpointer data) {&lt;br /&gt;    base_class_i = 100;&lt;br /&gt;    g_print("Calling base_class_init(): base_class_i=%d\n", base_class_i);&lt;br /&gt;    klass-&gt;base_instance_dump = base_instance_dump;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void base_instance_init(Base *instance, gpointer data) {&lt;br /&gt;    instance-&gt;base_instance_i = 200;&lt;br /&gt;    g_print("Calling base_instance_init(): base_instance_i=%d\n", instance-&gt;base_instance_i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GType base_get_type() {&lt;br /&gt;    static GType base_type = 0;&lt;br /&gt;    if (base_type == 0) {&lt;br /&gt;        static const GTypeInfo base_type_info = {&lt;br /&gt;            sizeof(BaseClass),  /* class_size */&lt;br /&gt;            NULL,               /* base_init */&lt;br /&gt;            NULL,               /* base_finalize */&lt;br /&gt;            (GClassInitFunc)base_class_init, /* class_init */&lt;br /&gt;            NULL,               /* class_finalize */&lt;br /&gt;            NULL,               /* class_data */&lt;br /&gt;            sizeof(Base),       /* instance_size */&lt;br /&gt;            0,                  /* n_preallocs */&lt;br /&gt;            (GInstanceInitFunc)base_instance_init, /* instance_init */&lt;br /&gt;            NULL                /* value_table */&lt;br /&gt;        };&lt;br /&gt;        GTypeFundamentalInfo foo_type_fundamental_info = {&lt;br /&gt;            G_TYPE_FLAG_CLASSED           /* Indicates a classed type */&lt;br /&gt;            | G_TYPE_FLAG_INSTANTIATABLE  /* Indicates an instantiable type */&lt;br /&gt;            | G_TYPE_FLAG_DERIVABLE       /* Indicates a flat derivable type */&lt;br /&gt;            | G_TYPE_FLAG_DEEP_DERIVABLE  /* Indicates a deep derivable type */&lt;br /&gt;        };&lt;br /&gt;        base_type = g_type_register_fundamental(g_type_fundamental_next(),&lt;br /&gt;            "BaseFundamentalType", &amp;base_type_info, &amp;foo_type_fundamental_info, 0);&lt;br /&gt;    }&lt;br /&gt;    return base_type;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In &lt;code&gt;base_instance_init()&lt;/code&gt;, we assigned the &lt;code&gt;base_instance_dump()&lt;/code&gt; callback. Thus, we can invoke this function by both global function or instance function of &lt;code&gt;BaseClass&lt;/code&gt; class. Additional flags &lt;code&gt;G_TYPE_FLAG_DERIVABLE&lt;/code&gt; and &lt;code&gt;G_TYPE_FLAG_DEEP_DERIVABLE&lt;/code&gt; are also passed to the &lt;code&gt;GTypeFundamentalInfo&lt;/code&gt; struct to enable inheritance. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; It's time to define our Derived type:&lt;br /&gt;&lt;pre class="brush: c"&gt;// derived.h&lt;br /&gt;#ifndef DERIVED_H_&lt;br /&gt;#define DERIVED_H_&lt;br /&gt;&lt;br /&gt;#include "base.h"&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;/* Derived object struct */&lt;br /&gt;typedef struct _Derived {&lt;br /&gt;    /* The GTypeClass structure is still the first member of the class structure */&lt;br /&gt;    Base parent;&lt;br /&gt;    /* should be hidden */&lt;br /&gt;    gint derived_instance_i;&lt;br /&gt;} Derived;&lt;br /&gt;&lt;br /&gt;/* Derived class struct */&lt;br /&gt;typedef struct _DerivedClass {&lt;br /&gt;    /* The TypeInstance structure is still the first member of the instance structure */&lt;br /&gt;    BaseClass parent;&lt;br /&gt;} DerivedClass;&lt;br /&gt;&lt;br /&gt;/* non-virtual public method for Derived object */&lt;br /&gt;void derived_instance_set_i(Derived *instance, gint i);&lt;br /&gt;&lt;br /&gt;/* (Overwrite) virtual public method for Derived object, both version are supported */&lt;br /&gt;void derived_instance_dump(Base *instance);&lt;br /&gt;&lt;br /&gt;/* type method */&lt;br /&gt;GType derived_get_type();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;#endif /* DERIVED_H_ */&lt;/pre&gt;&lt;pre class="brush: c"&gt;// derived.c&lt;br /&gt;#include "derived.h"&lt;br /&gt;&lt;br /&gt;void derived_instance_set_i(Derived *instance, gint i) {&lt;br /&gt;    instance-&gt;derived_instance_i = i;&lt;br /&gt;    g_print("Invoking derived_instance_set_i(): derived_instance_i=%d\n", instance-&gt;derived_instance_i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void derived_instance_dump(Base *instance) {&lt;br /&gt;    Derived *derived = G_TYPE_CHECK_INSTANCE_CAST(instance, derived_get_type(), Derived);&lt;br /&gt;    g_print("Invoking derived_instance_dump(): base_instance_i=%d, derived_instance_i=%d\n", instance-&gt;base_instance_i, derived-&gt;derived_instance_i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void derived_class_init(DerivedClass *klass, gpointer data) {&lt;br /&gt;    g_print("Calling derived_class_init()\n");&lt;br /&gt;    base_class_set_i(300);&lt;br /&gt;    /* override */&lt;br /&gt;    BaseClass *base_klass = G_TYPE_CHECK_CLASS_CAST(klass, base_get_type(), BaseClass);&lt;br /&gt;    base_klass-&gt;base_instance_dump = derived_instance_dump;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void derived_instance_init(Derived *instance, gpointer data) {&lt;br /&gt;    instance-&gt;derived_instance_i = 400;&lt;br /&gt;    g_print("Calling derived_instance_init(): derived_instance_i=%d\n", instance-&gt;derived_instance_i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;GType derived_get_type() {&lt;br /&gt;    static GType derived_type = 0;&lt;br /&gt;    if(derived_type == 0) {&lt;br /&gt;        static const GTypeInfo derived_type_info = {&lt;br /&gt;            sizeof(DerivedClass), /* class_size */&lt;br /&gt;            NULL,               /* base_init */&lt;br /&gt;            NULL,               /* base_finalize */&lt;br /&gt;            (GClassInitFunc)derived_class_init, /* class_init */&lt;br /&gt;            NULL,               /* class_finalize */&lt;br /&gt;            NULL,               /* class_data */&lt;br /&gt;            sizeof(Derived),    /* instance_size */&lt;br /&gt;            0,                  /* n_preallocs */&lt;br /&gt;            (GInstanceInitFunc)derived_instance_init, /* instance_init */&lt;br /&gt;            NULL                /* value_table */&lt;br /&gt;        };&lt;br /&gt;        derived_type = g_type_register_static(&lt;br /&gt;            base_get_type(), "DerivedStaticClass", &amp;derived_type_info, 0);&lt;br /&gt;    }&lt;br /&gt;    return derived_type;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Our &lt;code&gt;Derived&lt;/code&gt; type inherits &lt;code&gt;Base&lt;/code&gt; by replacing  &lt;code&gt;GTypeClass&lt;/code&gt; and &lt;code&gt;GTypeInstance&lt;/code&gt; with the corresponding struct of the Base type. According to the memory layout of structs, &lt;code&gt;GTypeClass&lt;/code&gt; and &lt;code&gt;GTypeInstance&lt;/code&gt; are still the first member of corresponding struct. In &lt;code&gt;derived_get_type()&lt;/code&gt;, we register &lt;code&gt;Derived&lt;/code&gt; type using &lt;code&gt;g_type_register_static()&lt;/code&gt; since it's not a fundamental at all. And the first parameter is the type id of &lt;code&gt;Base&lt;/code&gt; type. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Let's have some time to look up how to implement polymorphism. In &lt;code&gt;derived_class_init()&lt;/code&gt;, we re-assign the &lt;code&gt;base_instance_dump()&lt;/code&gt; callback to from the &lt;code&gt;Base&lt;/code&gt;'s implementation to &lt;code&gt;Derived&lt;/code&gt;'s implementation. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Test code:&lt;br /&gt;&lt;pre class="brush: c"&gt;int main() {&lt;br /&gt;    g_type_init();&lt;br /&gt;    my_dump_type(base_get_type());&lt;br /&gt;    my_dump_type(derived_get_type());&lt;br /&gt;&lt;br /&gt;    /*&lt;br /&gt;     * Official document:&lt;br /&gt;     * Use of g_type_create_instance() is reserved for implementators of&lt;br /&gt;     * fundamental types only. E.g. instances of the GObject hierarchy should&lt;br /&gt;     * be created via g_object_new() and never directly through&lt;br /&gt;     * g_type_create_instance() which doesn't handle things like singleton&lt;br /&gt;     * objects or object construction.&lt;br /&gt;     */&lt;br /&gt;    Base *base = (Base *)g_type_create_instance(base_get_type());&lt;br /&gt;    base_class_set_i(101);&lt;br /&gt;    base_instance_set_i(base, 201);&lt;br /&gt;    Derived *derived = (Derived *)g_type_create_instance(derived_get_type());&lt;br /&gt;    derived_instance_set_i(derived, 401);&lt;br /&gt;&lt;br /&gt;    /* Test polymorphism */&lt;br /&gt;    Base *instances[2] = { base, (Base *)derived };&lt;br /&gt;    int i;&lt;br /&gt;    for (i = 0; i &lt; 2; i++) {&lt;br /&gt;        Base *inst = instances[i];&lt;br /&gt;        BaseClass *klass = G_TYPE_INSTANCE_GET_CLASS(inst, base_get_type(), BaseClass);&lt;br /&gt;        klass-&gt;base_instance_dump(inst);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject4 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-7785509627315629305?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/7785509627315629305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=7785509627315629305&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7785509627315629305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7785509627315629305'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-4-inheritable-class.html' title='OOP Using GObject (4) - An Inheritable Class'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3290981268990832368</id><published>2011-03-11T16:10:00.002+08:00</published><updated>2011-03-15T16:44:31.392+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (3) - An Instantiatable Class</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; We will make fundamental type instantiatable and complete our first usage sample in this article. An object class should be defined firstly:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;/* Foo object struct */&lt;br /&gt;typedef struct _Foo {&lt;br /&gt;    /*&lt;br /&gt;     * Official document:&lt;br /&gt;     * All instance structures must contain as first member a TypeInstance structure.&lt;br /&gt;     */&lt;br /&gt;    GTypeInstance parent;&lt;br /&gt;    /* instance variable */&lt;br /&gt;    int foo_instance_i;&lt;br /&gt;} Foo;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Also, we re-define the class struct:&lt;pre class="brush: c"&gt;/* Foo class struct */&lt;br /&gt;typedef struct _FooClass {&lt;br /&gt;    /*&lt;br /&gt;     * Official document:&lt;br /&gt;     * All class structures must contain as first member a GTypeClass structure.&lt;br /&gt;     */&lt;br /&gt;    GTypeClass parent;&lt;br /&gt;} FooClass;&lt;br /&gt;&lt;br /&gt;/* static field of Foo class */&lt;br /&gt;int foo_class_i;&lt;br /&gt;&lt;br /&gt;/* static method of Foo class */&lt;br /&gt;void foo_class_set_i(int i) {&lt;br /&gt;    foo_class_i = i;&lt;br /&gt;    printf("Invoking foo_class_set_i(): foo_class_i=%d\n", foo_class_i);&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;GTypeClass&lt;/code&gt; should be the first member of a class struct, while &lt;code&gt;TypeInstance&lt;/code&gt; the first member of a object struct. You may wonder why there's two int variable in both struct. The &lt;code&gt;foo_class_i&lt;/code&gt; is like a static variable in C++ class, while The &lt;code&gt;foo_instance_i&lt;/code&gt; is like an instance variable in C++ class. And remember fields in a class struct? It is used as meta info. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The registry function also need modification:&lt;pre class="brush: c"&gt;GType foo_get_type() {&lt;br /&gt;    static GType foo_type = 0;&lt;br /&gt;    if (foo_type == 0) {&lt;br /&gt;        static const GTypeInfo foo_type_info = {&lt;br /&gt;            sizeof(FooClass),   /* class_size */&lt;br /&gt;            NULL,               /* base_init */&lt;br /&gt;            NULL,               /* base_finalize */&lt;br /&gt;            (GClassInitFunc)foo_class_init, /* class_init */&lt;br /&gt;            NULL,               /* class_finalize */&lt;br /&gt;            NULL,               /* class_data */&lt;br /&gt;            sizeof(Foo),        /* instance_size */&lt;br /&gt;            0,                  /* n_preallocs */&lt;br /&gt;            (GInstanceInitFunc)foo_instance_init, /* instance_init */&lt;br /&gt;            NULL                /* value_table */&lt;br /&gt;        };&lt;br /&gt;        /* G_TYPE_FLAG_INSTANTIATABLE: Indicates an instantiable type (implies classed) */&lt;br /&gt;        GTypeFundamentalInfo foo_type_fundamental_info = {&lt;br /&gt;            G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_INSTANTIATABLE&lt;br /&gt;        };&lt;br /&gt;        foo_type = g_type_register_fundamental(g_type_fundamental_next(),&lt;br /&gt;            "FooClassedFundamentalType", &amp;foo_type_info, &amp;foo_type_fundamental_info, 0);&lt;br /&gt;    }&lt;br /&gt;    return foo_type;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; We assigned the &lt;code&gt;instance_init()&lt;/code&gt; callback. It is called when a instance of our &lt;code&gt;Foo&lt;/code&gt; class is created. You may ask where is the corresponding &lt;code&gt;instance_finalize()&lt;/code&gt; callback? Hey, we will discuss it in upcoming articles. The &lt;code&gt;instance_init()&lt;/code&gt; callback can be regarded as the constructor of a C++ class. Note, an additional &lt;code&gt;G_TYPE_FLAG_INSTANTIATABLE&lt;/code&gt; flag is also added in the &lt;code&gt;GTypeFundamentalInfo&lt;/code&gt; struct. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Let's see how to create an instance:&lt;pre class="brush: c"&gt;int main() {&lt;br /&gt;    g_type_init();&lt;br /&gt;    my_dump_type(foo_get_type());&lt;br /&gt;&lt;br /&gt;    /* Use g_type_create_instance if implement a fundamental class */&lt;br /&gt;    Foo *foo = (Foo *)g_type_create_instance(foo_get_type());&lt;br /&gt;    foo_class_set_i(101);&lt;br /&gt;    foo_instance_set_i(foo, 201);&lt;br /&gt;&lt;br /&gt;    printf("Is instance of int? %s\n",&lt;br /&gt;        G_TYPE_CHECK_INSTANCE_TYPE(foo, G_TYPE_INT) ? "yes" : "no");&lt;br /&gt;    printf("Is instance of FooClassedFundamentalType? %s\n",&lt;br /&gt;        G_TYPE_CHECK_INSTANCE_TYPE(foo, foo_get_type()) ? "yes" : "no");&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Congratulations! You've finished the learning of our fundamental sample.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject3 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3290981268990832368?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3290981268990832368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3290981268990832368&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3290981268990832368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3290981268990832368'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-3-instantiatable.html' title='OOP Using GObject (3) - An Instantiatable Class'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2105561449582265710</id><published>2011-03-11T15:39:00.006+08:00</published><updated>2011-03-15T16:45:10.987+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (2) - A Classed Type</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; In last article, we defined a fundamental type. But nothing can be done with it. Now, we will extend it to be a classed type, say adding class info into our fundamental type. To do this, we should define a class struct, which can be regard as the meta info of a C++ class:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;typedef struct _FooClass {&lt;br /&gt;    /*&lt;br /&gt;     * Official document:&lt;br /&gt;     * All class structures must contain as first member a GTypeClass structure.&lt;br /&gt;     */&lt;br /&gt;    GTypeClass parent;&lt;br /&gt;    /*&lt;br /&gt;     * Since glib 2.24, there're new functions to keep privacy.&lt;br /&gt;     */&lt;br /&gt;    int i;&lt;br /&gt;    void (*bar)();&lt;br /&gt;} FooClass;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;GTypeClass&lt;/code&gt; should be the first member of a class struct. You can image the i field to be the version of the class. And we can add a string field to hold the author of this class. There's also a function pointer bar(). As you may already know, it is used to implement polymorphism, which can be regard as virtual function of a C++ class.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; When registering our fundamental type, additional field in &lt;code&gt;GTypeInfo&lt;/code&gt; and &lt;code&gt;GTypeFundamentalInfo&lt;/code&gt; are filled:&lt;br /&gt;&lt;pre class="brush: c"&gt;GType foo_get_type() {&lt;br /&gt;    static GType foo_type = 0;&lt;br /&gt;    if (foo_type == 0) {&lt;br /&gt;        static const GTypeInfo foo_type_info = {&lt;br /&gt;            sizeof(FooClass),   /* class_size */&lt;br /&gt;            NULL,               /* base_init */&lt;br /&gt;            NULL,               /* base_finalize */&lt;br /&gt;            (GClassInitFunc)foo_class_init, /* class_init */&lt;br /&gt;            NULL,               /* class_finalize */&lt;br /&gt;            NULL,               /* class_data */&lt;br /&gt;            0,                  /* instance_size */&lt;br /&gt;            0,                  /* n_preallocs */&lt;br /&gt;            NULL,               /* instance_init */&lt;br /&gt;            NULL                /* value_table */&lt;br /&gt;        };&lt;br /&gt;        /* G_TYPE_FLAG_CLASSED: Indicates a classed type */&lt;br /&gt;        GTypeFundamentalInfo foo_type_fundamental_info = { G_TYPE_FLAG_CLASSED };&lt;br /&gt;        foo_type = g_type_register_fundamental(g_type_fundamental_next(),&lt;br /&gt;            "FooClassedFundamentalType", &amp;amp;foo_type_info, &amp;amp;foo_type_fundamental_info, 0);&lt;br /&gt;    }&lt;br /&gt;    return foo_type;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;code&gt;GTypeInfo&lt;/code&gt; is the key data structure of GObject type system. It defines how a classed type should be initialized and finalized. Here, we just assigned the &lt;code&gt;class_init()&lt;/code&gt; callback. It is called when our &lt;code&gt;FooClass&lt;/code&gt; needs initialization. For fundamental and static types, their &lt;code&gt;class_finalize()&lt;/code&gt; are never called. We will demo the usage of this callback when introducing dynamic types. Please also note the &lt;code&gt;G_TYPE_FLAG_CLASSED&lt;/code&gt; flag passed into &lt;code&gt;GTypeFundamentalInfo&lt;/code&gt; struct. &amp;nbsp;&amp;nbsp;&amp;nbsp; Now, let's implement our &lt;code&gt;foo_class_init()&lt;/code&gt; function. This function is used to initialize fields and assign virtual functions in most time:&lt;pre class="brush: c"&gt;void foo_class_bar();&lt;br /&gt;&lt;br /&gt;void foo_class_init(FooClass *klass, gpointer data) {&lt;br /&gt;    klass-&gt;i = 129;&lt;br /&gt;    klass-&gt;bar = foo_class_bar;&lt;br /&gt;    printf("Calling foo_class_init(): i=%d\n", klass-&gt;i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void foo_class_bar() {&lt;br /&gt;    printf("Invoking foo_class_bar()\n");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now, we've finished our definition of the class struct. Let's see how to use it:&lt;pre class="brush: c"&gt;int main() {&lt;br /&gt;    g_type_init();&lt;br /&gt;    my_dump_type(foo_get_type());&lt;br /&gt;&lt;br /&gt;    FooClass *klass = (FooClass *)g_type_class_ref(foo_get_type());&lt;br /&gt;    klass-&gt;bar();&lt;br /&gt;    g_type_class_unref(klass);&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; See? We use &lt;code&gt;g_type_class_ref()&lt;/code&gt; and &lt;code&gt;g_type_class_unref()&lt;/code&gt; to ref/unref a class, and invoke a function. But its function is still limited. We can just get/set its meta info. It still cannot be instantiated. This will be discussed in the next article.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject2 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2105561449582265710?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2105561449582265710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2105561449582265710&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2105561449582265710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2105561449582265710'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-2-classed-type.html' title='OOP Using GObject (2) - A Classed Type'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5223705556445948490</id><published>2011-03-11T14:20:00.009+08:00</published><updated>2011-03-15T16:45:28.645+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GObject'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>OOP Using GObject (1) - A Fundamental Type</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; These days, I tried to write C code with OO support. I found &lt;a href="http://library.gnome.org/devel/gobject/stable/"&gt;GObject&lt;/a&gt; is such a well-designed library to simplify my implementation. However, the official documents is not so clear sometimes.&amp;nbsp; It do not provide sufficient information about all its stuff. I had to write my own demo applications to test the usage of some function. Moreover, the source code were also checked for reference. &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; There are 3 types in GObject type system: Fundamental, static and dynamic. Fundamental types are top-most types. The do not have parent types. They are seldom used, since all fundamental types are pre-defined rather than user-defined. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In this article, I will try to define a fundamental type using in GObject.Here's the code on how to register a basic fundamental type in GObject, and how it can be used. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: PLEASE READ ALL COMMENT CAREFULLY.&lt;br /&gt;&lt;pre class="brush: c"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;glib-object.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;    /* Initialize type system */&lt;br /&gt;    g_type_init();&lt;br /&gt;&lt;br /&gt;    /* This is not important */&lt;br /&gt;    GTypeInfo my_type_info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL };&lt;br /&gt;    /* This is not important */&lt;br /&gt;    GTypeFundamentalInfo my_type_fundamental_info = { 0 };&lt;br /&gt;    /* Register a fundamental type */&lt;br /&gt;    GType my_type_id = g_type_register_fundamental(g_type_fundamental_next(),&lt;br /&gt;        "MyFundamentalType", &amp;amp;my_type_info, &amp;amp;my_type_fundamental_info, 0);&lt;br /&gt;&lt;br /&gt;    /* Print type names */&lt;br /&gt;    printf("Type name of int: %s\n", g_type_name(G_TYPE_INT));&lt;br /&gt;    printf("Type name of float: %s\n", g_type_name(G_TYPE_FLOAT));&lt;br /&gt;    printf("Type name of object: %s\n", g_type_name(G_TYPE_OBJECT));&lt;br /&gt;    printf("Type name of my fundamental type: %s\n", g_type_name(my_type_id));&lt;br /&gt;    /* Print type id and name of MyFundamentalType */&lt;br /&gt;    printf("Type id: %d\n", g_type_from_name("MyFundamentalType"));&lt;br /&gt;    printf("Type name: %s\n", g_type_name(g_type_from_name("MyFundamentalType")));&lt;br /&gt;    /* Print attributes of MyFundamentalType */&lt;br /&gt;    printf("Is fundamental? %s\n", G_TYPE_IS_FUNDAMENTAL(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is derived? %s\n", G_TYPE_IS_DERIVED(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is interface? %s\n", G_TYPE_IS_INTERFACE(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is classed? %s\n", G_TYPE_IS_CLASSED(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is instantiatable? %s\n", G_TYPE_IS_INSTANTIATABLE(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is derivable? %s\n", G_TYPE_IS_DERIVABLE(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is deep derivable? %s\n", G_TYPE_IS_DEEP_DERIVABLE(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is abstract? %s\n", G_TYPE_IS_ABSTRACT(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is value abstract? %s\n", G_TYPE_IS_VALUE_ABSTRACT(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Is value type: %s\n", G_TYPE_IS_VALUE_TYPE(my_type_id) ? "yes" : "no");&lt;br /&gt;    printf("Has value table: %s\n", G_TYPE_HAS_VALUE_TABLE(my_type_id) ? "yes" : "no");&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; My fundamental type is created by calling &lt;code&gt;g_type_register_fundamental()&lt;/code&gt; function. A &lt;code&gt;GTypeInfo&lt;/code&gt; and a &lt;code&gt;GTypeFundamentalInfo&lt;/code&gt; struct are passed as parameters. And here comes the linux Makefile. You can use pkg-config to replace my include and lib paths:&lt;br /&gt;&lt;pre class="brush: plain"&gt;CC      := gcc&lt;br /&gt;CFLAGS  := -ansi -Wall&lt;br /&gt;INCPATH := -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include&lt;br /&gt;LIBS    := -lgobject-2.0&lt;br /&gt;TARGET  := TestGObject1&lt;br /&gt;OBJS    := main.o&lt;br /&gt;&lt;br /&gt;all: $(OBJS)&lt;br /&gt;    $(CC) $(CFLAGS) ${LIBS} $(OBJS) -o $(TARGET)&lt;br /&gt;&lt;br /&gt;%.o: %.c&lt;br /&gt;    $(CC) $(CFLAGS) $(INCPATH) -c $&amp;lt;&lt;br /&gt;&lt;br /&gt;clean:&lt;br /&gt;    rm -f *~&lt;br /&gt;    rm -f *.o&lt;br /&gt;    rm -f $(TARGET)&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;NOTE&lt;/b&gt;: REPLACE THE WHITESPACE WITH TAB IN MAKEFILES, IF YOU COPY THE CODE DIRECTLY.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The fundamental type is of no use at all presently. In the next article, I will extend my code to add class meta info.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; All source code is available in my skydrive: &lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO&lt;/a&gt;. In the TestGObject-{date}.zip/TestGObject1 folder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5223705556445948490?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5223705556445948490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5223705556445948490&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5223705556445948490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5223705556445948490'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/03/oop-using-gobject-1-fundamental-type.html' title='OOP Using GObject (1) - A Fundamental Type'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-6368288261852505970</id><published>2011-02-14T01:40:00.005+08:00</published><updated>2011-03-15T16:38:06.315+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='WebDAV'/><category scheme='http://www.blogger.com/atom/ns#' term='Apache'/><title type='text'>Using WebDAV in Apache</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; From wikipedia &lt;a href="http://en.wikipedia.org/wiki/WebDAV"&gt;http://en.wikipedia.org/wiki/WebDAV&lt;/a&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;Web-based Distributed Authoring and Versioning&lt;/b&gt; (&lt;b&gt;WebDAV&lt;/b&gt;) is a set of methods based on the Hypertext Transfer Protocol (HTTP) that facilitates collaboration between users in editing and managing documents and files stored on World Wide Web servers. WebDAV was defined in &lt;span class="external mw-magiclink-rfc"&gt;RFC 4918&lt;/span&gt; by a working group of the Internet Engineering Task Force (IETF).&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The WebDAV protocol makes the Web a readable and writable medium, in line with Tim Berners-Lee's original vision. It provides a framework for users to create, change and move documents on a server (typically a web server or "web share"). The most important features of the WebDAV protocol include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;locking ("overwrite prevention")&lt;/li&gt;&lt;li&gt;properties (creation, removal, and querying of information about author, modified date et cetera);&lt;/li&gt;&lt;li&gt;name space management (ability to copy and move Web pages within a server's namespace)&lt;/li&gt;&lt;li&gt;collections (creation, removal, and listing of resources)&lt;/li&gt;&lt;/ul&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I used Apache to experience the WebDAV. The server was built and installed from source with:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# ./configure --prefix=/usr/local/apache2 --with-layout=Apache --with-mpm=prefork --enable-mods-shared=all --enable-ssl&lt;br /&gt;# make&lt;br /&gt;# sudo make install&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The "prefix", "layout", "mpm" switch is not necessary, since these are the default values under Unix. Now modify the configure files to support WebDAV access:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# cd /usr/local/apache2&lt;br /&gt;# sudo mkdir var uploads&lt;br /&gt;# sudo chown -R daemon:daemon var uploads&lt;br /&gt;# sudo bin/htdigest -c user.passwd DAV-upload user&lt;br /&gt;# sudo bin/htdigest user.passwd DAV-upload admin &lt;/pre&gt;&amp;nbsp; &amp;nbsp; The "var" and "uploads" directory, the "DAV-upload" realm, "user.passwd" file, "user" and "admin" user account are referred by "conf/extra/webdav.conf". While the "daemon" user and group are referred by "conf/httpd.conf".&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then modify "httpd.conf" to include "webdav.conf" the apache server. It a single include directive. Now start the apache server by running:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo bin/apachectl start&lt;/pre&gt;&amp;nbsp; &amp;nbsp; Our WebDAV directory is /uploads. So here's the address on how to access it:&lt;br /&gt;In nautilus: dav://192.168.1.100/uploads&lt;br /&gt;In konquer: webdav://192.168.1.100/uploads&lt;br /&gt;In windows: Go to --&amp;gt; My Network Places --&amp;gt; Add a network place --&amp;gt; Internet or network address --&amp;gt; Enter (http://&amp;lt;user&amp;gt;:&amp;lt;password&amp;gt;@192.168.1.100/uploads) --&amp;gt; Finish!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-6368288261852505970?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/6368288261852505970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=6368288261852505970&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6368288261852505970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6368288261852505970'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/02/using-webdav-in-apache.html' title='Using WebDAV in Apache'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-8805031529342697327</id><published>2011-01-20T01:33:00.003+08:00</published><updated>2011-03-15T16:46:07.471+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Symbian'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><title type='text'>Symbian Development on Linux</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; This article borrows hugely from: &lt;a href="http://labs.qt.nokia.com/2010/12/17/experimental-packages-for-symbian-development-on-linux/"&gt;http://labs.qt.nokia.com/2010/12/17/experimental-packages-for-symbian-development-on-linux/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; First, there's Qt SDK and Nokia Qt SDK. In a word, Qt SDK is for desktop development, while Nokia Qt SDK is for mobile development. A detailed comparison can be found &lt;a href="http://qt.nokia.com/products/qt-for-mobile-platforms#qtfornokia"&gt;here&lt;/a&gt;. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then, there's S60 SDK. Is it necessary to install it before developing symbian applications? The S60 SDK is only available under Windows platform. Under Windows, Nokia Qt SDK is an all-in-one package. It includes S60 SDK, Qt SDK, QtSimulator and a Symbian compiler. So, the AIO package is recommended. There's another choice under Windows: S60 SDK + Qt for Symbian. The Symbian version can be found &lt;a href="http://qt.nokia.com/downloads/symbian-cpp"&gt;here&lt;/a&gt;. But this time, there's no simulator.&lt;br /&gt;&amp;nbsp; &amp;nbsp; As mentioned &lt;a href="http://labs.qt.nokia.com/2010/11/09/qt-4-7-1-released/"&gt;here&lt;/a&gt;, These two SDK will be merged in Nokia Qt SDK 1.1.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now, we will have our Linux tutorial for Ubuntu.&lt;br /&gt;1. Download and install the following packages (32-bit versions only):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * &lt;a href="http://pepper.troll.no/s60prereleases/linux-packages/gcce-4.4.172-r1.deb"&gt;gcce-4.4.172-r1.deb&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * &lt;a href="http://pepper.troll.no/s60prereleases/linux-packages/s60-sdk-5.0.deb"&gt;s60-sdk-5.0.deb&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * &lt;a href="http://pepper.troll.no/s60prereleases/linux-packages/runonphone-4.7.1.deb"&gt;runonphone-4.7.1.deb&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; * &lt;a href="http://pepper.troll.no/s60prereleases/linux-packages/qt-symbian-libs-4.7.1-r1.deb"&gt;qt-symbian-libs-4.7.1-r1.deb&lt;/a&gt; (Old version: &lt;a href="http://pepper.troll.no/s60prereleases/linux-packages/qt-symbian-libs-4.7.1.deb"&gt;qt-symbian-libs-4.7.1.deb&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;2. Install App TRK on your phone. It's a debug service. Find *.sisx files &lt;a href="http://tools.ext.nokia.com/trk/"&gt;here&lt;/a&gt;. Check the TRKPackages.xml file to get correct version for your phone. For my C5-03, I used s60_5_0_app_trk_3_2_7.sisx. &lt;br /&gt;&lt;br /&gt;3. Install Qt libs for Symbian. They can be found at Qt's ftp site: &lt;a href="ftp://ftp.qt.nokia.com/pub/qt/symbian/"&gt;ftp://ftp.qt.nokia.com/pub/qt/symbian/&lt;/a&gt;. I installed version 4.7.1 as the developing library. Here's what exactly each *.sis package contains: &lt;br /&gt;&lt;pre&gt;* fluidlauncher.sis&lt;br /&gt;Contains around 10 different Qt demos. Depends on Qt and Open C.&lt;br /&gt;* qt.sis&lt;br /&gt;Contains the Qt libraries Symbian Signed for Nokia phones. Depends on Open C.&lt;br /&gt;* qt_selfsigned.sis&lt;br /&gt;A self-signed version of the above library. Works on other phones such as the Samsung i8910.&lt;br /&gt;* qtwebkit.sis&lt;br /&gt;Contains the QtWebKit library Symbian Signed for Nokia phones. Depends on Qt.&lt;br /&gt;* qtwebkit_selfsigned.sis&lt;br /&gt;A self-signed version of the above library. Works on other phones such as the Samsung i8910.&lt;br /&gt;* qt_demos.sis&lt;br /&gt;Contains qt.sis, qtwebkit.sis, fluidlauncher.sis and Open C all in one convenient package. No other dependencies.&lt;br /&gt;* qt_installer.sis&lt;br /&gt;Contains qt.sis, qtwebkit.sis and Open C all in one convenient package. No other dependencies.&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Installing qt_installer.sis is enough.&lt;br /&gt;&lt;br /&gt;4. Configure your QtCreator, add QtSimulator and QtSymbian versions. The Qt4 page should be something like:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/5370531978/" title="qt_symbian_1"&gt;&lt;img alt="qt_symbian_1" border="0" height="334" src="http://farm6.static.flickr.com/5084/5370531978_ea924b3a87.jpg" width="500" /&gt;&amp;nbsp;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;5. Now, create a simple GUI application and add desktop/simulator/device targets, so that you can run on all of them. &lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/5370550738/" title="qt_symbian_2"&gt;&lt;img alt="qt_symbian_2" border="0" height="390" src="http://farm6.static.flickr.com/5082/5370550738_38aa276ae7.jpg" width="414" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;6. Run on phone. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; When App TRK is installed, connect the phone to the PC using the USB cable. Select "PCSuite" as connection type. Then run App TRK on the phone, and make sure that the connection type is USB. This can be changed under the Settings menu entry. If necessary, choose Connect from the menu.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; On Linux, phone should appear as the /dev/ttyUSB1 device, however if you are running an old kernel, you may need to force the USB module to be loaded correctly before the device will appear:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# lsusb&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Note the identifier on the line where your Symbian device appears. Then execute the following, using the first and second part of the identifier in place of XXX, respectively.&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo rmmod usbserial&lt;br /&gt;# sudo modprobe usbserial vendor=0x0XXX product=0x0XXX&lt;/pre&gt;&amp;nbsp; &amp;nbsp; For my C5-03, It's:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo modprobe usbserial vendor=0x0421 product=0x03e6&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The rmmod step may fail if the module is not already loaded, but that is harmless.&lt;br /&gt;&amp;nbsp; &amp;nbsp; In QtCreator, go to Projects --&amp;gt; Targets --&amp;gt; Symbian Device, refresh the serial port, select USB1 and connect to your phone.&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/5369971337/" title="qt_symbian_3"&gt;&lt;img alt="qt_symbian_3" border="0" height="323" src="http://farm6.static.flickr.com/5125/5369971337_67f5b51996.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Congratulations! you've done. Select Symbian device as your target and click run button. This will package, deploy and run your application on your phone. Simple, Huhhh?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-8805031529342697327?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/8805031529342697327/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=8805031529342697327&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8805031529342697327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8805031529342697327'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/01/symbian-development-on-linux.html' title='Symbian Development on Linux'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5084/5370531978_ea924b3a87_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2724336569203757114</id><published>2011-01-18T00:44:00.004+08:00</published><updated>2011-03-15T16:46:52.822+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Symbian'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Packaging a Qt Application</title><content type='html'>&amp;nbsp; &amp;nbsp; This article applies to Ubuntu 8.04/10.04. I referred to the instruction here: &lt;a href="http://ubuntuforums.org/showthread.php?t=51003"&gt;http://ubuntuforums.org/showthread.php?t=51003&lt;/a&gt;. And I'll use my &lt;a href="http://code.google.com/p/qansieditor/source/browse/trunk/qastrologer/"&gt;qastrologer&lt;/a&gt; project to demo the building procedure.&lt;br /&gt;&lt;br /&gt;1. Install build tool packages:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install build-essential dh-make debhelper devscripts&lt;/pre&gt;&lt;br /&gt;2. Get the source package, exact it into ~/packages/qastrologer. The directory structure should like: ~/packages/qastrologer/qastrologer-&amp;lt;version&amp;gt;/&amp;lt;source&amp;gt;. The &amp;lt;source&amp;gt; directory contains your *.pro file.&lt;br /&gt;&lt;br /&gt;3. Add install section in *.pro file. Otherwise, the built package contains not binary:&lt;br /&gt;&lt;pre class="brush: plain"&gt;unix {&lt;br /&gt;    isEmpty(PREFIX):PREFIX = /usr&lt;br /&gt;    BINDIR = $$PREFIX/bin&lt;br /&gt;    DATADIR = $$PREFIX/share&lt;br /&gt;    target.path = $$BINDIR&lt;br /&gt;    icon.path = $$DATADIR/icons/hicolor/scalable/apps&lt;br /&gt;    icon.files += qastrologer.svg&lt;br /&gt;    desktop.path = $$DATADIR/applications&lt;br /&gt;    desktop.files += qastrologer.desktop&lt;br /&gt;    INSTALLS += target icon desktop&lt;br /&gt;}&lt;/pre&gt;I referred to the guild here: &lt;a href="http://wiki.maemo.org/Packaging_a_Qt_application"&gt;http://wiki.maemo.org/Packaging_a_Qt_application&lt;/a&gt;. For more information on how to use the INSTALLS macro, refer to the Qt document: &lt;a href="http://doc.trolltech.com/4.7/qmake-environment-reference.html#installs"&gt;http://doc.trolltech.com/4.7/qmake-environment-reference.html#installs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;4. Run dh_make. This will create the basic debian package structure.&lt;br /&gt;&lt;pre class="brush: plain"&gt;# dh_make -s -c gpl --createorig&lt;/pre&gt;We are generating a single binary package and licensed with GPL. After running the command, a "debian" subdirectory is created. Now we need to fill in more useful infomations.&lt;br /&gt;&lt;br /&gt;5. "rules" file:&lt;br /&gt;It is the most important build script. The cdbs already have support for building QMake projects. Our "rules" file is simple:&lt;br /&gt;&lt;pre class="brush: plain"&gt;#!/usr/bin/make -f&lt;br /&gt;&lt;br /&gt;include /usr/share/cdbs/1/rules/debhelper.mk&lt;br /&gt;include /usr/share/cdbs/1/class/qmake.mk&lt;br /&gt;&lt;br /&gt;QMAKE = qmake-qt4&lt;/pre&gt;Last line ensures we use Qt4. I referred to the source of minitube project. You can access it via:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get source minitube&lt;/pre&gt;&lt;br /&gt;6. "control" file:&lt;br /&gt;This file controls build and binary dependency. For my qastrologer, the default values are enough. You may want to have some minor changes in "Section"/"Priority"/"Maintainer" values. Since I want to keep my package installs from 8.04 to 10.04 and above, I must specify the minimum dependencies manually to use Qt 4.3. So my "control" file looks like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;Source: qastrologer&lt;br /&gt;Section: network&lt;br /&gt;Priority: optional&lt;br /&gt;Maintainer: Binhao Qian &amp;lt;gonwan@gmail.com&amp;gt;&lt;br /&gt;Build-Depends: debhelper (&amp;gt;= 5), libcurl4-openssl-dev (&amp;gt;= 7.18), libqt4-dev (&amp;gt;= 4.3)&lt;br /&gt;Standards-Version: 3.7.2&lt;br /&gt;&lt;br /&gt;Package: qastrologer&lt;br /&gt;Architecture: any&lt;br /&gt;Depends: libcurl3 (&amp;gt;= 7.18),&lt;br /&gt;         libqt4-core (&amp;gt;= 4.3) | libqtcore4 (&amp;gt;= 4.3), libqt4-gui (&amp;gt;= 4.3) | libqtgui4 (&amp;gt;= 4.3)&lt;br /&gt;Description: Qt-based astrologer application&lt;br /&gt; Simple application to get astrologer information from sina.tw.&lt;/pre&gt;Note, the default "control" file uses "${shlibs:Depends}" and "${misc:Depends}" macros to generate binary dependencies automatically. Refer to the man page of debhelper to get more information.&lt;br /&gt;&lt;br /&gt;7. Fill in "changelog" and "copyright" files.&lt;br /&gt;&lt;br /&gt;8. Build the package:&lt;br /&gt;For full build of the package (build source, deb, clean...) run:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# dpkg-buildpackage -rfakeroot&lt;/pre&gt;Instead if you have a big package, you can also build only the deb file with:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# fakeroot debian/rules binary&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2724336569203757114?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2724336569203757114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2724336569203757114&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2724336569203757114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2724336569203757114'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2011/01/packaging-qt-application.html' title='Packaging a Qt Application'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-70195113408144168</id><published>2010-12-03T16:46:00.007+08:00</published><updated>2011-03-15T16:47:16.781+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><title type='text'>Speeding up Qt Building</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; As starting with version 4.4, the size of Qt source grows extremely fast. It take hours or even a entire afternoon to build it with full feature enabled. Since I do not use advanced features like Webkit or Phonon, I always build Qt with them disabled. I will show and explain my configure parameters in 4.3 and 4.6 in both windows and linux build in this article.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Windows Build&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; v4.3, just disable the qt3support module:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# configure -fast -no-qt3support&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; v4.6, more modules are disabled:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# configure -fast -no-qt3support -no-xmlpatterns -no-webkit -no-phonon -no-multimedia -no-script -no-scripttools -no-declarative -no-s60 -no-native-gestures&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Qt4.4 added concurrent, webkit, phonon and xmlpattern code, and the format of help files was changed.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Qt4.5 added the gtkstyle. In configure script, -make and -nomake switch are added. But official support for VC6 and VS2002 were dropped. Actually, VC6 generates incorrect code.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Qt4.6 added javascriptcore backend for QtScript module. So I added the "-no-script" switch.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Maybe you have noted, there's no "-no-make" switch exists before Qt4.5. So, how to exclude building of demos and examples? I looked into the v4.5 source code of configure.exe(located in $QTSRC/tools/configure), and found all "no-make" parts are just excluded by writing to a .qmake.cache file. After running configure, the .qmake.cache file may have a line like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;QT_BUILD_PARTS  = libs tools examples demos docs translations&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now just keep the first 2 entries.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Linux Build&lt;/b&gt;:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; From v4.6, there's only one all-in-one source package, no separate platform-specific source packages are provided. I firstly chose the qt-everywhere-opensource-src-4.6.3.zip. But even its configure script did not run. Finally, I found it's a line ending issue, and we need to convert it first using dos2unix utility.&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install tofrodos&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now convert line endings:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# dos2unix configure&lt;br /&gt;# find config.tests/ -type f | xargs dos2unix&lt;br /&gt;# find src/corelib/global/ -type f | xargs dos2unix&lt;br /&gt;# find mkspecs/ -type f | xargs dos2unix&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The first 3 lines ensure running of configure script. The last line ensures correct generation of makefiles. Without it, no separated debug info are generated and you may also encounter errors when linking the assistant application as described in &lt;a href="http://bugreports.qt.nokia.com/browse/QTBUG-5471"&gt;QTBUG-5471&lt;/a&gt;. The qt-everywhere-opensource-src-4.6.3.tar.gz with *nix line endings does not need above steps and may have less undiscovered build issues.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I've tested this approach under Hardy(Ubuntu8.04) and Lucid(Ubuntu10.04). Under Lucid, the dos2unix/unix2dos utility seems to be renamed to fromdos/todos. Just replace the command name.&lt;br /&gt;&amp;nbsp; &amp;nbsp; We can configure it now:&lt;br /&gt;&amp;nbsp; &amp;nbsp; v4.3, as easy as windows: &lt;br /&gt;&lt;pre class="brush: plain"&gt;# ./configure -prefix /usr/local -fast -no-qt3support&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; v4.6, we do not have s60 and gesture switches:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# ./configure -prefix /usr/local -fast -no-qt3support -no-xmlpatterns -no-webkit -no-phonon -no-multimedia -no-script -no-scripttools -no-declarative&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; After running configure, modify the .qmake.cache file to remove unnecessary entries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-70195113408144168?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/70195113408144168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=70195113408144168&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/70195113408144168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/70195113408144168'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/12/speed-up-qt-building.html' title='Speeding up Qt Building'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-6906189838869403844</id><published>2010-10-24T02:36:00.004+08:00</published><updated>2011-03-15T16:47:31.882+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QTerm'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><title type='text'>Patching QTerm</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Long time no post here. Recently, I reported 3 bugs to &lt;a href="http://qterm.sourceforge.net/wiki/index.php/Main_Page"&gt;QTerm&lt;/a&gt; project and patches were provided. This is my first time to contribute an open-source project. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then I was able to build my private patched debian package of QTerm with the guide &lt;a href="http://ubuntuforums.org/showthread.php?t=51003"&gt;here&lt;/a&gt;. I just use the official debian package meta info found in &lt;a href="http://mirror.lupaworld.com/ubuntu/pool/universe/q/qterm/"&gt;this mirror site&lt;/a&gt;. Some notes to take: &lt;br /&gt;1. The path should be like: /home/&amp;lt;your_name&amp;gt;/packages/&amp;lt;your_project&amp;gt;/&lt;br /&gt;2. Before running "dpkg-buildpackage -rfakeroot", check the debian/control file to see what packages is required to build. &lt;br /&gt;3. The revision of package seems to be controlled by debian/changelog. &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; My private build file can be found in my skydrive:&lt;br /&gt;For Hardy(8.04): &lt;a href="http://cid-481cbe104492a3af.office.live.com/self.aspx/share/dev/QAnsiEditor/qterm%5E_0.5.7-2%5E_i386.deb"&gt;QTerm 0.5.7&lt;/a&gt;&lt;br /&gt;For Lucid(10.04): &lt;a href="http://cid-481cbe104492a3af.office.live.com/self.aspx/share/dev/QAnsiEditor/qterm%5E_0.5.11-2%5E_i386.deb"&gt;QTerm 0.5.11&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-6906189838869403844?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/6906189838869403844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=6906189838869403844&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6906189838869403844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6906189838869403844'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/10/patching-qterm.html' title='Patching QTerm'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5973142776068856102</id><published>2010-09-21T01:28:00.024+08:00</published><updated>2011-03-15T17:05:03.064+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='MSVC'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>C++ Class Layout Using MSVC</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; The article is originally inspired by this one: &lt;a href="http://www.openrce.org/articles/full_view/23"&gt;http://www.openrce.org/articles/full_view/23&lt;/a&gt;. The undocumented parameters in MSVC++ compiler are: /d1reportSingleClassLayout&amp;lt;classname&amp;gt; and /d1reportAllClassLayout.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; A simple example: &lt;br /&gt;&lt;pre class="brush: cpp"&gt;class CBase {&lt;br /&gt;    int a;&lt;br /&gt;public:&lt;br /&gt;    virtual void foo() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class CDerived1: public CBase {&lt;br /&gt;    int a1;&lt;br /&gt;public:&lt;br /&gt;    virtual void foo1() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class CDerived2: virtual public CBase {&lt;br /&gt;    int a2;&lt;br /&gt;public:&lt;br /&gt;    virtual void foo() { }&lt;br /&gt;    virtual void foo2() { }&lt;br /&gt;};&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The dumped layout: &lt;br /&gt;&lt;pre&gt;class CBase size(8):&lt;br /&gt;        +---&lt;br /&gt; 0      | {vfptr}&lt;br /&gt; 4      | a&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CBase::$vftable@:&lt;br /&gt;        | &amp;amp;CBase_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CBase::foo&lt;br /&gt;&lt;br /&gt;CBase::foo this adjustor: 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class CDerived1 size(12):&lt;br /&gt;        +---&lt;br /&gt;        | +--- (base class CBase)&lt;br /&gt; 0      | | {vfptr}&lt;br /&gt; 4      | | a&lt;br /&gt;        | +---&lt;br /&gt; 8      | a1&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CDerived1::$vftable@:&lt;br /&gt;        | &amp;amp;CDerived1_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CBase::foo&lt;br /&gt; 1      | &amp;amp;CDerived1::foo1&lt;br /&gt;&lt;br /&gt;CDerived1::foo1 this adjustor: 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class CDerived2 size(20):&lt;br /&gt;        +---&lt;br /&gt; 0      | {vfptr}&lt;br /&gt; 4      | {vbptr}&lt;br /&gt; 8      | a2&lt;br /&gt;        +---&lt;br /&gt;        +--- (virtual base CBase)&lt;br /&gt;12      | {vfptr}&lt;br /&gt;16      | a&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CDerived2::$vftable@CDerived2@:&lt;br /&gt;        | &amp;amp;CDerived2_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CDerived2::foo2&lt;br /&gt;&lt;br /&gt;CDerived2::$vbtable@:&lt;br /&gt; 0      | -4&lt;br /&gt; 1      | 8 (CDerived2d(CDerived2+4)CBase)&lt;br /&gt;&lt;br /&gt;CDerived2::$vftable@CBase@:&lt;br /&gt;        | -12&lt;br /&gt; 0      | &amp;amp;CDerived2::foo&lt;br /&gt;&lt;br /&gt;CDerived2::foo this adjustor: 12&lt;br /&gt;CDerived2::foo2 this adjustor: 0&lt;br /&gt;&lt;br /&gt;vbi:       class  offset o.vbptr  o.vbte fVtorDisp&lt;br /&gt;           CBase      12       4       4 0&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You see: When using virtual inheritance, an additional vbptr is added into class layout. There is also a separated section containing the virtual base class, with vbptr pointing to it. So, the object size of virtual inheritance is bigger than non-virtual inheritance.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now, here is a complex example: &lt;br /&gt;&lt;pre class="brush: cpp"&gt;class CBase1 {&lt;br /&gt;    int a1;&lt;br /&gt;public:&lt;br /&gt;    virtual void foo1() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class CBase2 : public virtual CBase1 {&lt;br /&gt;    int a2;&lt;br /&gt;public:&lt;br /&gt;    virtual void foo2() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class CBase3 : public virtual CBase1 {&lt;br /&gt;    int a3;&lt;br /&gt;public:&lt;br /&gt;    virtual void foo3() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class CBase4 : public CBase1 {&lt;br /&gt;    int a4;&lt;br /&gt;public:&lt;br /&gt;    virtual void foo4() { }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class CDerive: public CBase2, public CBase3, public CBase4 {&lt;br /&gt;    int b;&lt;br /&gt;public:&lt;br /&gt;    virtual void bar() { }&lt;br /&gt;};&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The dumped layout: &lt;br /&gt;&lt;pre&gt;class CBase1 size(8):&lt;br /&gt;        +---&lt;br /&gt; 0      | {vfptr}&lt;br /&gt; 4      | a1&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CBase1::$vftable@:&lt;br /&gt;        | &amp;amp;CBase1_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CBase1::foo1&lt;br /&gt;CBase1::foo1 this adjustor: 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class CBase2 size(20):&lt;br /&gt;        +---&lt;br /&gt; 0      | {vfptr}&lt;br /&gt; 4      | {vbptr}&lt;br /&gt; 8      | a2&lt;br /&gt;        +---&lt;br /&gt;        +--- (virtual base CBase1)&lt;br /&gt;12      | {vfptr}&lt;br /&gt;16      | a1&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CBase2::$vftable@CBase2@:&lt;br /&gt;        | &amp;amp;CBase2_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CBase2::foo2&lt;br /&gt;&lt;br /&gt;CBase2::$vbtable@:&lt;br /&gt; 0      | -4&lt;br /&gt; 1      | 8 (CBase2d(CBase2+4)CBase1)&lt;br /&gt;&lt;br /&gt;CBase2::$vftable@CBase1@:&lt;br /&gt;        | -12&lt;br /&gt; 0      | &amp;amp;CBase1::foo1&lt;br /&gt;&lt;br /&gt;CBase2::foo2 this adjustor: 0&lt;br /&gt;&lt;br /&gt;vbi:       class  offset o.vbptr  o.vbte fVtorDisp&lt;br /&gt;          CBase1      12       4       4 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class CBase3 size(20):&lt;br /&gt;        +---&lt;br /&gt; 0      | {vfptr}&lt;br /&gt; 4      | {vbptr}&lt;br /&gt; 8      | a3&lt;br /&gt;        +---&lt;br /&gt;        +--- (virtual base CBase1)&lt;br /&gt;12      | {vfptr}&lt;br /&gt;16      | a1&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CBase3::$vftable@CBase3@:&lt;br /&gt;        | &amp;amp;CBase3_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CBase3::foo3&lt;br /&gt;&lt;br /&gt;CBase3::$vbtable@:&lt;br /&gt; 0      | -4&lt;br /&gt; 1      | 8 (CBase3d(CBase3+4)CBase1)&lt;br /&gt;&lt;br /&gt;CBase3::$vftable@CBase1@:&lt;br /&gt;        | -12&lt;br /&gt; 0      | &amp;amp;CBase1::foo1&lt;br /&gt;&lt;br /&gt;CBase3::foo3 this adjustor: 0&lt;br /&gt;&lt;br /&gt;vbi:       class  offset o.vbptr  o.vbte fVtorDisp&lt;br /&gt;          CBase1      12       4       4 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class CBase4 size(12):&lt;br /&gt;        +---&lt;br /&gt;        | +--- (base class CBase1)&lt;br /&gt; 0      | | {vfptr}&lt;br /&gt; 4      | | a1&lt;br /&gt;        | +---&lt;br /&gt; 8      | a4&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CBase4::$vftable@:&lt;br /&gt;        | &amp;amp;CBase4_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CBase1::foo1&lt;br /&gt; 1      | &amp;amp;CBase4::foo4&lt;br /&gt;&lt;br /&gt;CBase4::foo4 this adjustor: 0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class CDerive size(48):&lt;br /&gt;        +---&lt;br /&gt;        | +--- (base class CBase2)&lt;br /&gt; 0      | | {vfptr}&lt;br /&gt; 4      | | {vbptr}&lt;br /&gt; 8      | | a2&lt;br /&gt;        | +---&lt;br /&gt;        | +--- (base class CBase3)&lt;br /&gt;12      | | {vfptr}&lt;br /&gt;16      | | {vbptr}&lt;br /&gt;20      | | a3&lt;br /&gt;        | +---&lt;br /&gt;        | +--- (base class CBase4)&lt;br /&gt;        | | +--- (base class CBase1)&lt;br /&gt;24      | | | {vfptr}&lt;br /&gt;28      | | | a1&lt;br /&gt;        | | +---&lt;br /&gt;32      | | a4&lt;br /&gt;        | +---&lt;br /&gt;36      | b&lt;br /&gt;        +---&lt;br /&gt;        +--- (virtual base CBase1)&lt;br /&gt;40      | {vfptr}&lt;br /&gt;44      | a1&lt;br /&gt;        +---&lt;br /&gt;&lt;br /&gt;CDerive::$vftable@CBase2@:&lt;br /&gt;        | &amp;amp;CDerive_meta&lt;br /&gt;        |  0&lt;br /&gt; 0      | &amp;amp;CBase2::foo2&lt;br /&gt; 1      | &amp;amp;CDerive::bar&lt;br /&gt;&lt;br /&gt;CDerive::$vftable@CBase3@:&lt;br /&gt;        | -12&lt;br /&gt; 0      | &amp;amp;CBase3::foo3&lt;br /&gt;&lt;br /&gt;CDerive::$vftable@:&lt;br /&gt;        | -24&lt;br /&gt; 0      | &amp;amp;CBase1::foo1&lt;br /&gt; 1      | &amp;amp;CBase4::foo4&lt;br /&gt;&lt;br /&gt;CDerive::$vbtable@CBase2@:&lt;br /&gt; 0      | -4&lt;br /&gt; 1      | 36 (CDerived(CBase2+4)CBase1)&lt;br /&gt;&lt;br /&gt;CDerive::$vbtable@CBase3@:&lt;br /&gt; 0      | -4&lt;br /&gt; 1      | 24 (CDerived(CBase3+4)CBase1)&lt;br /&gt;&lt;br /&gt;CDerive::$vftable@CBase1@:&lt;br /&gt;        | -40&lt;br /&gt; 0      | &amp;amp;CBase1::foo1&lt;br /&gt;&lt;br /&gt;CDerive::func5 this adjustor: 0&lt;br /&gt;&lt;br /&gt;vbi:       class  offset o.vbptr  o.vbte fVtorDisp&lt;br /&gt;          CBase1      40       4       4 0&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The layout of CDerive class is so complicated. First, it has 3 base classes, 1 field and 1 virtual base section. The the first 2 base classes(CBase2, CBase3) have their vbptr pointed to the address of the virtual base section.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5973142776068856102?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5973142776068856102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5973142776068856102&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5973142776068856102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5973142776068856102'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/09/c-class-layout-using-msvc.html' title='C++ Class Layout Using MSVC'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-8577684630935494747</id><published>2010-08-12T15:05:00.005+08:00</published><updated>2011-03-15T17:06:34.998+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Gnome'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Fix Window Button Order in Lucid</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; I read this &lt;a href="http://motersho.com/blog/index.php/2010/03/08/fix-minimizemaximizeclose-button-order-in-ubuntu-10-04-lucid-lynx/"&gt;article&lt;/a&gt; when Lucid was just released. It works good, but there's no window icon in the title bar(See my previous screen-shots).&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then I tried to modify the theme files. Take "Radiance" theme as example:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo gedit /usr/share/themes/Radiance/index.theme&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Change the last line into:&lt;br /&gt;&lt;pre class="brush: plain"&gt;ButtonLayout=menu:minimize,maximize,close&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; This will set your window button order. And every time you switch to "Radiance" theme, no confirm dialog will prompt to tell that the button order will be changed. Then:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo gedit /usr/share/themes/Radiance/metacity-1/metacity-theme-1.xml&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Search "menu_focused_normal", there are four lines regarding graphics drawing of menu: "menu_focused_normal", "menu_focused_prelight", "menu_unfocused_prelight", "menu_unfocused_prelight". Add first line into "menu_focused_*" and remove the image tag, and use second line to replace the image tag in "menu_unfocused_*" too.&lt;br /&gt;&lt;pre class="brush: xml"&gt;&amp;lt;icon x="(width-mini_icon_width)/2" y="(height-mini_icon_height)/2" width="mini_icon_width" height="mini_icon_height" /&amp;gt;&lt;br /&gt;&amp;lt;icon x="(width-mini_icon_width)/2" y="(height-mini_icon_height)/2" width="mini_icon_width" height="mini_icon_height" alpha="0.5" /&amp;gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; OK, you're done.&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4884126279/"&gt;&lt;img height="375" src="http://farm5.static.flickr.com/4078/4884126279_515ee61a8f.jpg" width="500" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-8577684630935494747?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/8577684630935494747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=8577684630935494747&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8577684630935494747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8577684630935494747'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/08/fix-window-button-order-in-lucid.html' title='Fix Window Button Order in Lucid'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4078/4884126279_515ee61a8f_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2498189052585852844</id><published>2010-07-17T01:44:00.002+08:00</published><updated>2011-03-15T16:40:03.345+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='GDM'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Remote Control in GDM Stage</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; In company, I use VNC to control remote machines. But in GDM  stage, this does not work. Maybe VNC server in Ubuntu is a service in  Gnome session. The solution is to use XDMCP(X Display Manager Control  Protocol). Using Ubuntu, "xnest" package should be installed on both  server and client side. It's a nested X server that simply relays all  its requests to another X server, where it runs as a client:&lt;br /&gt;#  sudo apt-get install xnest&lt;br /&gt;&amp;nbsp; &amp;nbsp; In server side,&amp;nbsp; go to System  --&amp;gt; Administration --&amp;gt; Login Window, or simply run "gdmsetup". Go  to "Remote" tab, set value to "Same as Local".&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; In client side, go to Applications --&amp;gt; Internet --&amp;gt;  Terminal Server Client, or simply run "tsclient". You'll find the XDMCP  protocol type can be selected now. Enter your server address to  connect.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Here's my screenshot. The output of command "who" and "ifconfig" had different IP addresses: &lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4799757878/"&gt;&amp;nbsp;&lt;img height="389" src="http://farm5.static.flickr.com/4136/4799757878_9182b870a3.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Since xnest sends and receive all X Server data, it consumes a lot of bandwith. On my laptop using wireless networking, it's somewhat slow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2498189052585852844?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2498189052585852844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2498189052585852844&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2498189052585852844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2498189052585852844'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/07/remote-control-in-gdm-stage.html' title='Remote Control in GDM Stage'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4136/4799757878_9182b870a3_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1460911244911160534</id><published>2010-07-17T01:13:00.002+08:00</published><updated>2011-03-15T16:39:30.888+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Metacity Compositing</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; I installed &lt;a href="http://www.glx-dock.org/"&gt;Cairo-Dock&lt;/a&gt; when installing Lucid. And it automatically enabled some desktop effects. Nowadays, I found these effects make my desktop less responsive. So, I decided to turn off them. First, I thought they were compiz effects. I was wrong. Actually, they are metacity compositing effects and come with gnome 2.22 and later versions.&lt;br /&gt;To disable them, run:&lt;br /&gt;# gconftool-2 -s '/apps/metacity/general/compositing_manager' --type  bool false&lt;br /&gt;And this command to enable them:&lt;br /&gt;# gconftool-2 -s '/apps/metacity/general/compositing_manager' --type bool true&lt;br /&gt;&lt;br /&gt;Additional info:&lt;br /&gt;&lt;a href="http://blogs.gnome.org/metacity/category/compositing/"&gt;http://blogs.gnome.org/metacity/category/compositing/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1460911244911160534?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1460911244911160534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1460911244911160534&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1460911244911160534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1460911244911160534'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/07/metacity-compositing.html' title='Metacity Compositing'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3736930867453519656</id><published>2010-07-14T02:36:00.006+08:00</published><updated>2011-03-15T16:48:16.681+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QTerm'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><title type='text'>Hacking QTerm</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; I read source code in &lt;a href="http://www.qterm.org/"&gt;QTerm&lt;/a&gt; and &lt;a href="http://code.google.com/p/fqterm/"&gt;FQTerm&lt;/a&gt; today. Since I want to find reference for Ascii rendering control in my &lt;a href="http://code.google.com/p/qansieditor/"&gt;QAnsiEditor&lt;/a&gt; project. After hours of tracing and debugging, I was able to use the rendering control in simplest code. Here's the patch in src/main.cpp:&lt;br /&gt;&lt;pre class="brush: diff"&gt;diff -ruN qterm-0.5.7/src/main.cpp qterm-0.5.7-1/src/main.cpp&lt;br /&gt;--- qterm-0.5.7/src/main.cpp 2009-06-14 23:09:32.000000000 +0800&lt;br /&gt;+++ qterm-0.5.7-1/src/main.cpp 2010-07-14 09:53:06.000000000 +0800&lt;br /&gt;@@ -16,6 +16,9 @@&lt;br /&gt; #include "qtermconfig.h"&lt;br /&gt; #include "qtermglobal.h"&lt;br /&gt; #include "qterm.h"&lt;br /&gt;+#include "qtermparam.h"&lt;br /&gt;+#include "qtermwindow.h"&lt;br /&gt;+#include "qtermscreen.h"&lt;br /&gt; &lt;br /&gt; #include &amp;lt;QtGlobal&amp;gt;&lt;br /&gt; #include &amp;lt;QApplication&amp;gt;&lt;br /&gt;@@ -139,12 +142,27 @@&lt;br /&gt;         return -1;&lt;br /&gt;     }&lt;br /&gt; &lt;br /&gt;-    QTerm::Frame * mw = new QTerm::Frame();&lt;br /&gt;-    mw-&gt;setWindowTitle( "QTerm "+QString(QTERM_VERSION) );&lt;br /&gt;-    mw-&gt;setWindowIcon( QPixmap(Global::instance()-&gt;pathLib()+"pic/qterm.png") );&lt;br /&gt;-    mw-&gt;show();&lt;br /&gt;-    a.connect( &amp;a, SIGNAL(lastWindowClosed()), &amp;a, SLOT(quit()) );&lt;br /&gt;-    int res = a.exec();&lt;br /&gt;+    //QTerm::Frame * mw = new QTerm::Frame();&lt;br /&gt;+    //mw-&gt;setWindowTitle( "QTerm "+QString(QTERM_VERSION) );&lt;br /&gt;+    //mw-&gt;setWindowIcon( QPixmap(Global::instance()-&gt;pathLib()+"pic/qterm.png") );&lt;br /&gt;+    //mw-&gt;show();&lt;br /&gt;+    //a.connect( &amp;a, SIGNAL(lastWindowClosed()), &amp;a, SLOT(quit()) );&lt;br /&gt;+    //int res = a.exec();&lt;br /&gt;+&lt;br /&gt;+    using namespace QTerm;&lt;br /&gt;+    Global::instance()-&gt;setScrollPosition(Global::Hide);&lt;br /&gt;+    Param param;&lt;br /&gt;+    param.m_BBSCode = "GBK";&lt;br /&gt;+    param.m_nDispCode = 0;&lt;br /&gt;+    param.m_strAddr = "bbs.yanxi.org";&lt;br /&gt;+    //param.m_nProxyType = 4;&lt;br /&gt;+    //param.m_strProxyHost = "gsopanel";&lt;br /&gt;+    //param.m_uProxyPort = 8000;&lt;br /&gt;+    Window *win = new QTerm::Window(0, param);&lt;br /&gt;+    win-&gt;setAttribute(Qt::WA_DeleteOnClose);&lt;br /&gt;+    win-&gt;setMinimumSize(600, 400);&lt;br /&gt;+    win-&gt;show();&lt;br /&gt; &lt;br /&gt;+    int res = a.exec();&lt;br /&gt;     return res;&lt;br /&gt; }&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The screenshot of standalone mode:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4791037730/"&gt;&lt;img height="357" src="http://farm5.static.flickr.com/4138/4791037730_4246bd8302.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The complete patch and patched source can be found here:&lt;br /&gt;&lt;a href="http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/QAnsiEditor"&gt;http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/QAnsiEditor&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3736930867453519656?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3736930867453519656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3736930867453519656&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3736930867453519656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3736930867453519656'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/07/hacking-qterm.html' title='Hacking QTerm'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4138/4791037730_4246bd8302_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2881642939458733714</id><published>2010-07-09T20:15:00.006+08:00</published><updated>2011-03-15T16:40:47.888+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><category scheme='http://www.blogger.com/atom/ns#' term='SVN'/><title type='text'>Using SVN in Ubuntu</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Since I chose SVN as my VCS in google code, a SVN GUI client may be helpful. I found kdesvn. It's free, powerful, and just there in the Ubuntu repository:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install kdesvn&lt;br /&gt;# sudo apt-get install konqueror&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The 2nd line is used to fix the bookmark issue in kdesvn :).&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then invoke the line below first:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# svn help&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; This will create a default configuration directory for SVN in ~/.subversion/. In fact, any SVN command will do. There are configuration files located in /etc/subversion/. But they seems to be of no use.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Note, kdesvn will use SVN configuration files when perform operations. Now, we need to edit them.&lt;br /&gt;1. Proxy:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gedit ~/.subversion/servers &amp;amp;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Uncomment and modify the following lines in [global] section:&lt;br /&gt;&lt;pre class="brush: plain"&gt;http-proxy-host = &amp;lt;your_http_proxy_host&amp;gt;&lt;br /&gt;http-proxy-port = &amp;lt;your_http_proxy_port&amp;gt;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; It seems that we can use separate settings for different host groups. This is not verified, leaves to you.&lt;br /&gt;2. Password:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; SVN 1.6 added gnome/gnome-keyring and kde/kwallet credentials management support. Some additional options were introduced.&lt;br /&gt;2.1 SVN 1.4.6 (Ubuntu 8.04, Hardy)&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gedit ~/.subversion/config &amp;amp;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Uncomment and modify the following lines in [auth] section:&lt;br /&gt;&lt;pre class="brush: plain"&gt;store-passwords = no&lt;br /&gt;store-auth-creds = no&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You're done. The 1st option prevents SVN from saving plain-text password locally. The 2nd even stops caching the credentials. Then every time you need an SVN authentication, a prompt appears.&lt;br /&gt;&amp;nbsp; &amp;nbsp; Note: you cannot find an option in kdesvn's configuration to set a user/password values. The application just use cached key values in ~/.subversion/auth/ directory.&lt;br /&gt;&lt;br /&gt;2.2 SVN 1.6.6 (Ubuntu 10.04, Lucid)&lt;br /&gt;&amp;nbsp; &amp;nbsp; If you do not want to save password, set the 2 values as that in Hardy. But they are deprecated and moved to ~/.subversion/servers.&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gedit ~/.subversion/servers &amp;amp;&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Uncomment and modify the following lines in [global] section:&lt;br /&gt;&lt;pre class="brush: plain"&gt;store-passwords = no&lt;br /&gt;store-auth-creds = no&lt;/pre&gt;&amp;nbsp; &amp;nbsp; Then the ~/.subversion/config file:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gedit ~/.subversion/config &amp;amp;&lt;/pre&gt;&amp;nbsp; &amp;nbsp; Uncomment and modify the following lines in [auth] section. Set to empty:&lt;br /&gt;&lt;pre class="brush: plain"&gt;password-stores =&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You're done! All SVN behaviors are consistent with that in Hardy.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If you want to integrate with gnome-keyring or kwallet, modify the line to contain "gnome-keyring", "kwallet" or both. Gnome-keyring does not integrate well with SVN, so I chose kwallet and have a test.&lt;br /&gt;&amp;nbsp; &amp;nbsp; In kdesvn, go to&amp;nbsp; Settings --&amp;gt; Configure Kdesvn --&amp;gt; Subversion, check the "Store passwords into KDE Kwallet" option. It's the default configuration. Make sure that the option and the "password-stores" value are consistent. Otherwise, our kdesvn fail to commit code. When a kdesvn prompts to ask for username/password, check "Store password (into KDE Wallet)" option. Then you can view your saved login information in KWallet Manager application:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4777151306/"&gt;&lt;img height="389" src="http://farm5.static.flickr.com/4080/4777151306_6f5435338d.jpg" width="479" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Some other screenshot of kdesvn in Lucid:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Main Window:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4777151300/"&gt;&lt;img height="305" src="http://farm5.static.flickr.com/4080/4777151300_c50f5feb2f.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Revision Tree:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4777151304/"&gt;&lt;img height="419" src="http://farm5.static.flickr.com/4134/4777151304_67dd3a7f40.jpg" width="500" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2881642939458733714?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2881642939458733714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2881642939458733714&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2881642939458733714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2881642939458733714'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/07/using-svn.html' title='Using SVN in Ubuntu'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4080/4777151306_6f5435338d_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-4944141115222417596</id><published>2010-07-08T14:31:00.004+08:00</published><updated>2011-03-15T17:42:52.013+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QTerm'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><title type='text'>2 Projects on Google Code</title><content type='html'>1. QSkin: &lt;a href="http://code.google.com/p/qskin/"&gt;http://code.google.com/p/qskin/&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QSkin is a framework for easier skinning Windows GUI applications. It  uses hook technologies, so applications can apply a skin with almost no  changes. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The initial 'Q' comes from my last name. :)&lt;br /&gt;&lt;br /&gt;2. QAnsiEditor: &lt;a href="http://code.google.com/p/qansieditor/"&gt;http://code.google.com/p/qansieditor/&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QAnsiEditor is a program to edit Ansi graphics. It aims to run on  multiple platforms base on Qt library. &lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; I will start to code the 2nd project first. Hope I can update it daily.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Release early, release often. =.=&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-4944141115222417596?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/4944141115222417596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=4944141115222417596&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4944141115222417596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4944141115222417596'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/07/2-projects-on-google-code.html' title='2 Projects on Google Code'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1889668339041203114</id><published>2010-07-08T01:17:00.004+08:00</published><updated>2011-03-15T16:49:08.521+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Debug'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Using Ubuntu Debug Packages in GDB (2)</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; From last blog, I've demostrated the usage of Ubuntu *-dbg packages. However, not all *-dbg packages seem to work as libssl0.9.8-dbg. For instance, libcurl3-dbg and libqt4-dbg packages do not work. I'm afraid some debug info are missing in these two packages. I'm not sure. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I googled a lot, but was not able to find a solution. So I decided to build the debug version of the two library myself. Here are steps for libcurl:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get source libcurl3-dbg&lt;br /&gt;# cd curl-7.19.7/&lt;br /&gt;# ./configure --prefix=/usr/local --enable-debug --enable-static=0&lt;br /&gt;# make&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; After all, the compiled binary is located in /home/gonwan/testgdb/curl-7.19.7/lib/.libs/. &lt;b&gt;Note&lt;/b&gt;, this is a hidden folder. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Here comes our test code:&lt;br /&gt;&lt;pre class="brush: c"&gt;#include &amp;lt;curl/curl.h&amp;gt;&lt;br /&gt;int main() {&lt;br /&gt;    curl_easy_init();&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Build commands:&lt;br /&gt;&lt;pre class="brush: plain"&gt;gcc -g testcurl.c -o testcurl /usr/lib/libcurl.so.4&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I use /usr/lib/libcurl.so.4 instead of lcurl, since lcurl will link the binary to /usr/lib/libcurl-gnutls.so.4. But I currently cannot afford it :(. Last, start our GDB:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# LD_LIBRARY_PATH=/home/gonwan/testgdb/curl-7.19.7/lib/.libs/ gdb ./testcurl&lt;br /&gt;GNU gdb (GDB) 7.1-ubuntu&lt;br /&gt;...&lt;br /&gt;Reading symbols from /home/gonwan/testgdb/testcurl...done.&lt;br /&gt;(gdb) b 3&lt;br /&gt;Breakpoint 1 at 0x8048572: file testcurl.c, line 3.&lt;br /&gt;(gdb) r&lt;br /&gt;Starting program: /home/gonwan/testgdb/testcurl&lt;br /&gt;[Thread debugging using libthread_db enabled]&lt;br /&gt;Breakpoint 1, main () at testcurl.c:3&lt;br /&gt;3           curl_easy_init();&lt;br /&gt;(gdb) s&lt;br /&gt;curl_easy_init () at easy.c:372&lt;br /&gt;372         if(!initialized) {&lt;br /&gt;(gdb) bt&lt;br /&gt;#0  curl_easy_init () at easy.c:372&lt;br /&gt;#1  0x08048577 in main () at testcurl.c:3&lt;br /&gt;(gdb) &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; It prints the backtrace now, though I'm not so accustomed to console debugging. I add the LD_LIBRARY_PATH environment to let our test program find our homemade version of libcurl.so.4. In fact, we can run ldd like following lines. You see the re-direction?&lt;br /&gt;&lt;pre class="brush: plain"&gt;# ldd ./testcurl | grep libcurl&lt;br /&gt;    libcurl.so.4 =&amp;gt; /usr/lib/libcurl.so.4 (0x00943000)&lt;br /&gt;# LD_LIBRARY_PATH=/home/gonwan/testgdb/curl-7.19.7/lib/.libs/ ldd ./testcurl | grep libcurl&lt;br /&gt;    libcurl.so.4 =&amp;gt; /home/gonwan/testgdb/curl-7.19.7/lib/.libs/libcurl.so.4 (0x00318000) &lt;/pre&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Later, I successfully made it possible to debug Qt source code in IDE. I chose QtCreator, since it has both windows and linux version, and it's easy to install and configure. I also built my homemade version of Qt:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get source libqt4-dbg&lt;br /&gt;# cd qt4-x11-4.6.2/&lt;br /&gt;# ./configure -prefix /usr/local -debug-and-release -no-qt3support -no-webkit -no-script -no-scripttools -no-xmlpatterns -no-phonon -no-multimedia -no-declarative -make libs -nomake tools -nomake examples -nomake demos -nomake docs -nomake translations -fast&lt;br /&gt;# make&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I only built the most common modules, excluding webkit, script, xmlpatterns, phonon, multimedia and declarative modules. It took only 25 minutes to finish (An entire build under windows may take 3 - 4 hours.). After all, start your QtCreator, create a Qt console project with the source below:&lt;br /&gt;&lt;pre class="brush: c"&gt;#include &amp;lt;QtCore/QString&amp;gt;&lt;br /&gt;int main() {&lt;br /&gt;    QString s = "1234567";&lt;br /&gt;    int i = s.indexOf('3');&lt;br /&gt;    return i != 2;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Build the project in debug mode. And now, here's the magic: Go to Project tab --&amp;gt; Run Settings --&amp;gt; Run Environment, append our homemade Qt library path to LD_LIBRARY_PATH. In my example, it's /home/gonwan/testgdb/qt4-x11-4.6.2/lib. Ok, you're almost done! Go back to the Edit tab, set a breakpoint at line 4 (or line 3 as you like), press F5 to start debugging the project. Then continue pressing F11, you will find GDB has stepped into Qt source code! Let me take a screenshot:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4771327153/"&gt;&lt;img height="385" src="http://farm5.static.flickr.com/4120/4771327153_243000e8de.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In order to load our homemade *.so, we can also run "make install".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1889668339041203114?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1889668339041203114/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1889668339041203114&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1889668339041203114'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1889668339041203114'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/07/using-ubuntu-debug-packages-in-gdb-2.html' title='Using Ubuntu Debug Packages in GDB (2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4120/4771327153_243000e8de_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-328222113716200228</id><published>2010-07-07T11:05:00.002+08:00</published><updated>2011-03-15T16:49:28.584+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Debug'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Using Ubuntu Debug Packages in GDB</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; I will use openssl library as example. Here's a simplest source:&lt;br /&gt;&lt;pre class="brush: c"&gt;#include &amp;lt;openssl/ssl.h&amp;gt;&lt;br /&gt;int main() {&lt;br /&gt;    SSL_library_init();&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now build and start your GDB, note the '-g' option is necessary:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gcc -g testopenssl.c -o testopenssl -lssl&lt;br /&gt;# gdb ./testopenssl&lt;br /&gt;GNU gdb 6.8-debian&lt;br /&gt;...&lt;br /&gt;(gdb) b 3&lt;br /&gt;Breakpoint 1 at 0x8048495: file testopenssl.c, line 3.&lt;br /&gt;(gdb) r&lt;br /&gt;Starting program: /home/binson/testgdb/testopenssl&lt;br /&gt;Breakpoint 1, main () at testopenssl.c:3&lt;br /&gt;3       SSL_library_init();&lt;br /&gt;(gdb) s&lt;br /&gt;4       return 0;&lt;br /&gt;(gdb) &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; GDB cannot step into openssl source code, since there's no debug symbol found. In Ubuntu, we can install it using apt-get. I'm using Hardy(8.04):&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install libssl0.9.8-dbg&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Launch our GDB again:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gdb ./testopenssl&lt;br /&gt;GNU gdb 6.8-debian&lt;br /&gt;...&lt;br /&gt;(gdb) b 3&lt;br /&gt;Breakpoint 1 at 0x8048495: file testopenssl.c, line 3.&lt;br /&gt;(gdb) r&lt;br /&gt;Starting program: /home/binson/testgdb/testopenssl&lt;br /&gt;Breakpoint 1, main () at testopenssl.c:3&lt;br /&gt;3       SSL_library_init();&lt;br /&gt;(gdb) s&lt;br /&gt;SSL_library_init () at ssl_algs.c:68&lt;br /&gt;68  ssl_algs.c: No such file or directory.&lt;br /&gt;    in ssl_algs.c&lt;br /&gt;(gdb) &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Symbols are found, GDB prompt for missing source files! We can install by typing:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get source libssl0.9.8&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The source files will be downloaded and extracted in openssl-0.9.8g folder. Now we wanna attach the source files when debugging.&lt;br /&gt;&lt;pre class="brush: plain"&gt;# gdb ./testopenssl&lt;br /&gt;GNU gdb 6.8-debian&lt;br /&gt;...&lt;br /&gt;(gdb) dir openssl-0.9.8g/ssl/&lt;br /&gt;Source directories searched: /home/binson/testgdb/openssl-0.9.8g/ssl:$cdir:$cwd&lt;br /&gt;(gdb) b 3&lt;br /&gt;Breakpoint 1 at 0x8048495: file testopenssl.c, line 3.&lt;br /&gt;(gdb) r&lt;br /&gt;Starting program: /home/binson/testgdb/testopenssl&lt;br /&gt;Breakpoint 1, main () at testopenssl.c:3&lt;br /&gt;3       SSL_library_init();&lt;br /&gt;(gdb) s&lt;br /&gt;SSL_library_init () at ssl_algs.c:68&lt;br /&gt;68      EVP_add_cipher(EVP_des_cbc());&lt;br /&gt;(gdb) bt&lt;br /&gt;#0  SSL_library_init () at ssl_algs.c:68&lt;br /&gt;#1  0x0804849a in main () at testopenssl.c:3&lt;br /&gt;(gdb) &lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Oh! Everything works!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-328222113716200228?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/328222113716200228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=328222113716200228&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/328222113716200228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/328222113716200228'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/07/using-ubuntu-debug-packages-in-gdb.html' title='Using Ubuntu Debug Packages in GDB'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-4194373550168624351</id><published>2010-06-18T01:53:00.007+08:00</published><updated>2011-03-15T16:49:48.254+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><title type='text'>Running Old Linux Kernel 0.11</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; Old kernels have less code. So They are easier to learn and understand. I follow the instructions here: &lt;a href="http://www.oldlinux.org/"&gt;http://www.oldlinux.org/&lt;/a&gt;. You can also download the eBook in the website(In Chinese).&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I managed to run the kernel in Hardy(8.04) and Lucid(10.04) using Bochs simulator. In Ubuntu, you may install it by typing:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install bochs bochs-x bochsbios vgabios&lt;/pre&gt;&amp;nbsp; &amp;nbsp; To compile the source, you may also want to install the assembler:&lt;br /&gt;&lt;pre class="brush: plain"&gt;# sudo apt-get install bin86&lt;/pre&gt;&amp;nbsp; &amp;nbsp; I downloaded the source here: &lt;a href="http://www.oldlinux.org/Linux.old/kernel/0.1x/linux-0.11-040327-rh9.tar.gz"&gt;http://www.oldlinux.org/Linux.old/kernel/0.1x/linux-0.11-040327-rh9.tar.gz&lt;/a&gt;. But it works only in RedHat 9(RHEL3, CentOS3) with gcc-3.2 and bochs-2.2. Then I patched the source code with the help of google. Finally, it compiled under gcc-4.1/gcc-4.2 and ran happily. Due to optimization issues, gcc-4.3 and above build the wrong kernel. I do not know how to solve this. I also downloaded the Bochs harddisk image here: &lt;a href="http://oldlinux.org/Linux.old/bochs/linux-0.11-devel-060625.zip"&gt;http://oldlinux.org/Linux.old/bochs/linux-0.11-devel-060625.zip&lt;/a&gt;.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; You may encounter syntax error using the including bochs configure file. Refer to a sample one found in /usr/share/doc/bochs/examples/bochsrc.gz. Basically, you should specify the image path of your floppy(kernel image) and harddisk like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;floppya: 1_44="./linux-0.11-gcc4.1/Image", status=inserted&lt;br /&gt;ata0-master: type=disk, path="./linux-0.11-devel-060625/hdc-0.11-new.img", mode=flat, cylinders=410, heads=16, spt=38&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then make sure the boot option is:&lt;br /&gt;&lt;pre class="brush: plain"&gt;boot: floppy&lt;/pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Now let's see the screenshot when running the classic kernel:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4709029731/"&gt;&lt;img border="0" height="332" src="http://farm2.static.flickr.com/1289/4709029731_2168683ab5.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; My patched code can be found here:&lt;br /&gt;Lucid(gcc-4.1):&amp;nbsp; &lt;iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://cid-481cbe104492a3af.office.live.com/embedicon.aspx/share/dev/%21Linux/linux-0.11-gcc4.1.tar.gz" style="background-color: #fcfcfc; height: 115px; padding: 0pt; width: 98px;" title="Preview"&gt;&lt;/iframe&gt;&amp;nbsp; Hardy(gcc-4.2):&amp;nbsp; &lt;iframe frameborder="0" marginheight="0" marginwidth="0" scrolling="no" src="http://cid-481cbe104492a3af.office.live.com/embedicon.aspx/share/dev/%21Linux/linux-0.11-gcc4.2.tar.gz" style="background-color: #fcfcfc; height: 115px; padding: 0pt; width: 98px;" title="Preview"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-4194373550168624351?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/4194373550168624351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=4194373550168624351&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4194373550168624351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4194373550168624351'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/06/running-old-linux-kernel-011.html' title='Running Old Linux Kernel 0.11'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm2.static.flickr.com/1289/4709029731_2168683ab5_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2337596063511507712</id><published>2010-06-03T00:49:00.008+08:00</published><updated>2011-03-15T16:40:18.708+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Gnome'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Compact Gnome Theme in Hardy</title><content type='html'>Refer to: &lt;a href="http://martin.ankerl.com/2008/10/10/how-to-make-a-compact-gnome-theme/"&gt;http://martin.ankerl.com/2008/10/10/how-to-make-a-compact-gnome-theme/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I chosen the Glossy theme and made a compact one. I tried to make smallest changes and it was enough. &lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo cp -r /usr/share/themes/Glossy/ /usr/share/themes/GlossyCompact/&lt;br /&gt;cd /usr/share/themes/GlossyCompact/&lt;br /&gt;sudo gedit index.theme&lt;/pre&gt;Modify the name and comments, save.&lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo gedit gtk-2.0/gtkrc&lt;/pre&gt;Add the following line:&lt;br /&gt;&lt;pre class="brush: plain"&gt;gtk-icon-sizes = "panel-menu=20,20:gtk-menu=16,16:gtk-button=16,16:gtk-small-toolbar=16,16:gtk-large-toolbar=20,20:gtk-dnd=32,32:gtk-dialog=32,32"&lt;/pre&gt;&lt;br /&gt;Ok, now let's compare the result:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4641411335/" title="theme_glossy"&gt;&lt;img src="http://farm5.static.flickr.com/4021/4641411335_ebeec6b293_m.jpg" width="240" height="208" alt="theme_glossy" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4641411233/" title="theme_glossy_compact"&gt;&lt;img src="http://farm4.static.flickr.com/3380/4641411233_05716ff8a5_m.jpg" width="240" height="208" alt="theme_glossy_compact" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2337596063511507712?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2337596063511507712/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2337596063511507712&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2337596063511507712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2337596063511507712'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/06/compact-gnome-theme-in-hardy.html' title='Compact Gnome Theme in Hardy'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4021/4641411335_ebeec6b293_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-4916841651414093209</id><published>2010-05-20T01:18:00.010+08:00</published><updated>2011-03-15T16:52:33.151+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Updating Kernel in Lucid (3)</title><content type='html'>Today, I built the mainline kernel v2.6.33.4 on Lucid. Most instruments were taken from here: &lt;a href="https://wiki.ubuntu.com/KernelTeam/GitKernelBuild"&gt;https://wiki.ubuntu.com/KernelTeam/GitKernelBuild&lt;/a&gt;: &lt;br /&gt;&lt;br /&gt;1. Unpack:&lt;br /&gt;&lt;pre class="brush: plain"&gt;tar -jxf linux-2.6.33.4.tar.bz2&lt;/pre&gt;&lt;br /&gt;2. Config:&lt;br /&gt;&lt;pre class="brush: plain"&gt;cd linux-2.6.33.4&lt;br /&gt;cp /boot/config-`uname -r` .config&lt;br /&gt;yes '' | make oldconfig&lt;br /&gt;make menuconfig&lt;/pre&gt;The last line is optional. The wiki said:&lt;br /&gt;&lt;blockquote&gt;Note that Ubuntu kernels build with debugging information on, which makes the resulting kernel modules (*.ko files) much larger than they would otherwise be (linux-image*.deb will be 200-300 MB instead of 20-30 MB). To turn this off, go into "Kernel hacking"; then, under "Kernel debugging", turn off "Compile the kernel with debug info".&lt;/blockquote&gt;&lt;span style="font-weight: bold;"&gt;It's outdated maybe.&lt;/span&gt; When building kernel 2.6.24.x in Hardy, It WAS 200-300MB. But in Lucid, it is always 20-30MB. When you turn off the option, the build process took 80min instead of 100min, and 800MB instead of 5G storage. The option is configured by "CONFIG_DEBUG_KERNEL" in .config file. &lt;br /&gt;&lt;br /&gt;3. Build:&lt;br /&gt;&lt;pre class="brush: plain"&gt;make-kpkg clean&lt;br /&gt;CONCURRENCY_LEVEL=`getconf _NPROCESSORS_ONLN` fakeroot make-kpkg --initrd --append-to-version=-custom --revision=2.6.33.4-1 kernel_image kernel_headers&lt;/pre&gt;After all, two files were generated. It contains 2772 modules. You may find the usage of "--append-to-version" and "--revision" options here:&lt;br /&gt;*) linux-headers-2.6.33.4-custom_2.6.33.4-1_i386.deb&lt;br /&gt;*) linux-image-2.6.33.4-custom_2.6.33.4-1_i386.deb&lt;br /&gt;&lt;br /&gt;4. Install:&lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo dpkg -i linux-headers-2.6.33.4-custom_2.6.33.4-1_i386.deb&lt;br /&gt;sudo dpkg -i linux-image-2.6.33.4-custom_2.6.33.4-1_i386.deb&lt;br /&gt;sudo update-initramfs -c -k 2.6.33.4-custom&lt;br /&gt;sudo update-grub&lt;/pre&gt;The last 2 lines are &lt;span style="font-weight: bold;"&gt;NOT&lt;/span&gt; mentioned in the wiki. They are used to generate the initrd image in Lucid. The build also do not generate abi and vmcoreinfo files in /boot. &lt;br /&gt;&lt;br /&gt;5. Reference:&lt;br /&gt;&lt;a href="http://ubuntuforums.org/showthread.php?p=9120942"&gt;http://ubuntuforums.org/showthread.php?p=9120942&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-4916841651414093209?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/4916841651414093209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=4916841651414093209&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4916841651414093209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/4916841651414093209'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/05/updating-kernel-in-lucid-3.html' title='Updating Kernel in Lucid (3)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-991107018832307773</id><published>2010-05-18T23:27:00.015+08:00</published><updated>2011-03-15T16:52:46.201+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Updating Kernel in Lucid (2)</title><content type='html'>　　It seems a little easier when building Lucid kernel from ubuntu source. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1. Tools:&lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo apt-get install fakeroot kernel-wedge build-essential makedumpfile kernel-package&lt;/pre&gt;&lt;br /&gt;2. Sources:&lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo apt-get source linux-source-2.6.32&lt;/pre&gt;&lt;br /&gt;3. Customize:&lt;br /&gt;　　cd into "linux-2.6.32" root. &lt;br /&gt;　　I selected "core2" as my custom name. &lt;br /&gt;&lt;pre class="brush: plain"&gt;cp debian.master/control.d/vars.generic debian.master/control.d/vars.core2&lt;br /&gt;cp debian.master/abi/2.6.32-21.32/i386/generic debian.master/abi/2.6.32-21.32/i386/core2&lt;br /&gt;cp debian.master/abi/2.6.32-21.32/i386/generic.modules debian.master/abi/2.6.32-21.32/i386/core2.modules&lt;br /&gt;cp debian.master/config/i386/config.flavour.generic debian.master/config/i386/config.flavour.core2&lt;/pre&gt;　　Then patch some files:&lt;br /&gt;*) debian.master/etc/getabis:&lt;br /&gt;From: getall i386 generic generic-pae 386&lt;br /&gt;To: getall i386 generic generic-pae 386 core2&lt;br /&gt;*) debian.master/rules.d/i386.mk:&lt;br /&gt;From: flavours = generic generic-pae 386&lt;br /&gt;To: flavours = generic generic-pae 386 core2&lt;br /&gt;　　Now, edit the config file. You will have to go through all the flavors for this script to work properly:&lt;br /&gt;&lt;pre class="brush: plain"&gt;debian/rules editconfigs&lt;/pre&gt;　　You should not make changes to any of the configurations until you see the core2 configuration:&lt;br /&gt;&lt;pre class="brush: plain"&gt;* Run menuconfig on i386/config.flavour.core2... Press a key.&lt;/pre&gt;　　I disabled the "Kernel hacking ==&gt; Kernel debugging" feature to accelerate build process. If you got the error like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;debian/scripts/misc/kernelconfig: line 121: /home/gonwan/linux-2.6.32/debian/scripts/misc/splitconfig.pl: Permission denied&lt;/pre&gt;　　Simply add the x permission to all scripts, it's a &lt;a href="https://bugs.launchpad.net/ubuntu/+source/linux/+bug/273437"&gt;known bug&lt;/a&gt;:&lt;br /&gt;&lt;pre class="brush: plain"&gt;chmod +x debian/scripts/*&lt;br /&gt;chmod +x debian/scripts/misc/*&lt;/pre&gt;&lt;br /&gt;4. Build:&lt;br /&gt;&lt;pre class="brush: plain"&gt;fakeroot debian/rules clean&lt;br /&gt;CONCURRENCY_LEVEL=2 AUTOBUILD=1 NOEXTRAS=1 skipabi=true fakeroot debian/rules binary-core2&lt;/pre&gt;　　If you got the error like:&lt;br /&gt;&lt;pre class="brush: plain"&gt;II: Checking modules for core2...&lt;br /&gt;reading new modules...read 2674 modules.&lt;br /&gt;reading old modules...&lt;br /&gt;MISS: dccp_probe&lt;br /&gt;read 2675 modules : new(0)  missing(1)&lt;br /&gt;EE: Missing modules (start begging for mercy)&lt;/pre&gt;　　Add option "skipmodule=true" to the last command line. If you got:&lt;br /&gt;&lt;pre class="brush: plain"&gt;get_debug_info: Can't create a handle for a new debug session.&lt;br /&gt;makedumpfile Failed.&lt;/pre&gt;　　Add option "no_dumpfile=true" to the last command line. And there will be no vmcoreinfo-2.6.32-22-core2 file. &lt;br /&gt;&lt;br /&gt;5. Done:&lt;br /&gt;　　I found that Lucid has 2675 driver modules while Hardy has only 1921. It seems the kernel was greatly enhanced between the two releases. &lt;br /&gt;　　My T60 has a Duo Core 1.83G CPU. It took about 90 minutes to finish. The kernel also consumed about 4G storage T.T. After all, two *.deb files were generated:&lt;br /&gt;*) linux-headers-2.6.32-22-core2_2.6.32-22.33_i386.deb&lt;br /&gt;*) linux-image-2.6.32-22-core2_2.6.32-22.33_i386.deb&lt;br /&gt;&lt;br /&gt;6. Others:&lt;br /&gt;　　Since the build process used so much storage, I was monitor my available disk space from time to time using "df" utility. I found the "free space" is about 500M larger than "available space". What happened? Then I found the answer here: &lt;a href="http://ubuntuforums.org/showthread.php?t=328786&amp;page=3"&gt;http://ubuntuforums.org/showthread.php?t=328786&amp;page=3&lt;br /&gt;&lt;/a&gt;. We can use "tune2fs" utility to set the size of reserved space:&lt;br /&gt;&lt;blockquote&gt;Set the percentage of the filesystem which may only be allocated by privileged processes. Reserving some number of filesystem blocks for use by privileged processes is done to avoid filesystem fragmentation, and to allow system daemons, such as syslogd(8), to continue to function correctly after non-privileged processes are prevented from writing to the filesystem. Normally, the default percentage of reserved blocks is 5%. &lt;/blockquote&gt;&lt;br /&gt;7. Reference:&lt;br /&gt;&lt;a href="https://help.ubuntu.com/community/Kernel/Compile"&gt;https://help.ubuntu.com/community/Kernel/Compile&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.avirtualhome.com/2010/05/05/how-to-compile-a-ubuntu-lucid-kernel/"&gt;http://blog.avirtualhome.com/2010/05/05/how-to-compile-a-ubuntu-lucid-kernel/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-991107018832307773?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/991107018832307773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=991107018832307773&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/991107018832307773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/991107018832307773'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/05/updating-kernel-in-lucid-2.html' title='Updating Kernel in Lucid (2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5434842234882955873</id><published>2010-05-18T01:38:00.012+08:00</published><updated>2011-03-15T16:52:56.006+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Updating Kernel in Hardy</title><content type='html'>　　Hardy(8.04) is a little different from all the other versions when building a kernel. Only Hardy has two packages for kernel installation: linux-image, linux-ubuntu-modules. If you do not install the latter one, your sound card and network card will can not be recognized. &lt;br /&gt;　　Today, I built the kernel from the &lt;span style="font-weight:bold;"&gt;ubuntu source&lt;/span&gt;(not the original kernel source). So, I could use the including debian scripts for convenience. Here's the steps: &lt;br /&gt;&lt;br /&gt;1. Tools:&lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo apt-get install build-essential fakeroot linux-kernel-devel kernel-wedge&lt;/pre&gt;&lt;br /&gt;2. Sources:&lt;br /&gt;　　The source will be downloaded in the current directory.&lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo apt-get source linux-source-2.6.24&lt;br /&gt;sudo apt-get source linux-ubuntu-modules-2.6.24&lt;/pre&gt;&lt;br /&gt;3. Customize:&lt;br /&gt;　　cd into "linux-2.6.24" root.&lt;br /&gt;　　I selected "core2" as my custom name.&lt;br /&gt;&lt;pre class="brush: plain"&gt;cp debian/control.d/vars.generic debian/control.d/vars.core2&lt;br /&gt;cp debian/abi/2.6.24-27.68/i386/generic debian/abi/2.6.24-27.68/i386/core2&lt;br /&gt;cp debian/abi/2.6.24-27.68/i386/generic.modules debian/abi/2.6.24-27.68/i386/core2.modules&lt;br /&gt;cat debian/config/i386/config debian/config/i386/config.generic &gt; debian/config/i386/config.core2&lt;/pre&gt;　　Then patch some files:&lt;br /&gt;*) debian/scripts/misc/getabis:&lt;br /&gt;From: getall i386 386 generic server virtual&lt;br /&gt;To: getall i386 386 generic server virtual core2&lt;br /&gt;*) debian/rules.d/i386.mk:&lt;br /&gt;From: flavours = 386 generic&lt;br /&gt;To: flavours = 386 generic core2&lt;br /&gt;&lt;br /&gt;4. Build:&lt;br /&gt;&lt;pre class="brush: plain"&gt;fakeroot debian/rules clean&lt;br /&gt;CONCURRENCY_LEVEL=2 AUTOBUILD=1 NOEXTRAS=1 skipabi=true fakeroot debian/rules binary-core2&lt;/pre&gt;　　If you get errors like:&lt;br /&gt;&gt; /home/gonwan/Documents/linux-2.6.24 is not clean, please run 'make mrproper'&lt;br /&gt;&gt; in the '/home/gonwan/Documents/linux-2.6.24' directory.&lt;br /&gt;　　Run the following command, it is issued by the Makefile:&lt;br /&gt;&lt;pre class="brush: plain"&gt;rm -rf .config include/config&lt;/pre&gt;&lt;br /&gt;5. Done:&lt;br /&gt;　　My PC has a P4-2.6c CPU. It took about 90 minutes to finish. The kernel also consumed about 2G storage. After all, three *.deb files were generated:&lt;br /&gt;*) linux-headers-2.6.24-27-core2_2.6.24-27.69_i386.deb&lt;br /&gt;*) linux-image-2.6.24-27-core2_2.6.24-27.69_i386.deb&lt;br /&gt;*) linux-image-debug-2.6.24-27-core2_2.6.24-27.69_i386.deb&lt;br /&gt;&lt;br /&gt;6. Customize modules:&lt;br /&gt;　　First, generate prepare scripts:&lt;br /&gt;&lt;pre class="brush: plain"&gt;cat debian/config/i386/config debian/config/i386/config.generic &gt; .config&lt;br /&gt;make prepare scripts&lt;/pre&gt;　　cd into "linux-ubuntu-modules-2.6.24-2.6.24"&lt;br /&gt;&lt;pre class="brush: plain"&gt;cp debian/control.d/vars.generic debian/control.d/vars.core2&lt;/pre&gt;　　Note: Custom modules name must match the custom kernel name, say "core2". &lt;br /&gt;　　Then patch some files:&lt;br /&gt;*) debian/rules.d/i386.mk:&lt;br /&gt;From: flavours = 386 generic&lt;br /&gt;To: flavours = 386 generic core2&lt;br /&gt;*) debian/rules.d/0-common-vars.mk (To prevent error in build step, debian/rules.d/3-udebs.mk):&lt;br /&gt;From: disable_d_i = no&lt;br /&gt;To: disable_d_i = true&lt;br /&gt;　　Now generate new debian/control, which includes new custom kernel:&lt;br /&gt;&lt;pre class="brush: plain"&gt;rm debian/control.stub&lt;br /&gt;debian/rules debian/control.stub&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;7. Build modules:&lt;br /&gt;&lt;pre class="brush: plain"&gt;AUTOBUILD=1 fakeroot debian/rules binary-arch arch=i386 flavours=core2 KDIR=/home/gonwan/Documents/linux-2.6.24&lt;/pre&gt;&lt;br /&gt;8. Done again:&lt;br /&gt;　　This time, it took 30 minutes and consumed 300M storage. Two *.deb files were built:&lt;br /&gt;*) linux-headers-lum-2.6.24-27-core2_2.6.24-27.45_i386.deb&lt;br /&gt;*) linux-ubuntu-modules-2.6.24-27-core2_2.6.24-27.45_i386.deb&lt;br /&gt;&lt;br /&gt;9. Install kernel:&lt;br /&gt;　　Just double-click or install using the dpkg utility. Here's my screen-shot:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4616309778/"&gt;&lt;img src="http://farm5.static.flickr.com/4071/4616309778_6ffc815e60.jpg" width="500" height="435" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;10. Reference:&lt;br /&gt;&lt;a href="https://help.ubuntu.com/community/Kernel/Compile"&gt;https://help.ubuntu.com/community/Kernel/Compile&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.avirtualhome.com/2009/09/08/how-to-compile-a-kernel-for-ubuntu-jaunty-revised/"&gt;http://blog.avirtualhome.com/2009/09/08/how-to-compile-a-kernel-for-ubuntu-jaunty-revised/&lt;/a&gt;&lt;br /&gt;&lt;a href="http://ubuntuforums.org/showthread.php?t=912322"&gt;http://ubuntuforums.org/showthread.php?t=912322&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5434842234882955873?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5434842234882955873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5434842234882955873&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5434842234882955873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5434842234882955873'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/05/updating-kernel-in-hardy.html' title='Updating Kernel in Hardy'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4071/4616309778_6ffc815e60_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-8787321657077186139</id><published>2010-05-16T23:58:00.005+08:00</published><updated>2011-03-15T16:53:05.188+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Updating Kernel in Lucid</title><content type='html'>　　Today, I updated my kernel using the official *.deb file to 2.6.33.3. This may be the easiest way: &lt;a href="http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.33.3-lucid/"&gt;http://kernel.ubuntu.com/~kernel-ppa/mainline/v2.6.33.3-lucid/&lt;/a&gt;. Since 2.6.33 supports DRM natively, my update was so smoothly. &lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4612244390/"&gt;&lt;img src="http://farm5.static.flickr.com/4003/4612244390_fd3b965293.jpg" width="500" height="491" /&gt;&lt;/a&gt;&lt;br /&gt;　　In the later 2 blogs, I want to learn and write down how to compile kernel from ubuntu source and original kernel source.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-8787321657077186139?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/8787321657077186139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=8787321657077186139&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8787321657077186139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8787321657077186139'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/05/updating-kernel-in-lucid.html' title='Updating Kernel in Lucid'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4003/4612244390_fd3b965293_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-8710251213601415627</id><published>2010-05-14T23:52:00.006+08:00</published><updated>2011-03-15T16:51:06.428+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Ubuntu to Mainline Kernel Version Mapping</title><content type='html'>　　I'm now using Ubuntu 10.04 (Lucid Lynx). I want to dig into the kernel. When I check the kernel package in Synaptic, I found the version is 2.6.32-22.33, but currently the mainline kernel version is 2.6.32.13. How could that be?　&lt;br /&gt;　　Then I found the following address: &lt;a href="http://kernel.ubuntu.com/%7Ekernel-ppa/info/kernel-version-map.html"&gt;http://kernel.ubuntu.com/~kernel-ppa/info/kernel-version-map.html&lt;/a&gt;. There's a map, and version 2.6.32-22.33 maps to mainline version 2.6.32.11+drm33.2. DRM stands for Direct Rendering Manager. It's a backport module from 2.6.33 to &lt;a href="http://en.wikipedia.org/wiki/Direct_Rendering_Manager"&gt;provide video acceleration&lt;/a&gt;.&lt;br /&gt;　　To further verify the version, I install the linux-source package. In /usr/src/linux-source-2.6.32.tar.bz2!/linux-source-2.6.32/Makefile:&lt;br /&gt;&lt;pre class="brush: plain"&gt;VERSION = 2&lt;br /&gt;PATCHLEVEL = 6&lt;br /&gt;SUBLEVEL = 32&lt;br /&gt;EXTRAVERSION = .11+drm33.2&lt;/pre&gt;&lt;br /&gt;　　But it is a modified version. To get the original kernel package, run the command:&lt;br /&gt;&lt;pre class="brush: plain"&gt;sudo apt-get source linux-source-2.6.32&lt;/pre&gt;&lt;br /&gt;　　There files will be downloaded: linux_2.6.32-22.33.dsc, linux_2.6.32.orig.tar.gz, linux_2.6.32-22.33.diff.gz. *.dsc is a signature, *.orig.tar.gz is the original source, *.diff.gz is the patch. In the case of packages made specifically for ubuntu, the last of these is not downloaded and the first usually won't have "orig" in the name. In /usr/src/linux-source-2.6.32.orig.tar.gz!/linux-source-2.6.32/Makefile:&lt;br /&gt;&lt;pre class="brush: plain"&gt;VERSION = 2&lt;br /&gt;PATCHLEVEL = 6&lt;br /&gt;SUBLEVEL = 32&lt;br /&gt;EXTRAVERSION = &lt;/pre&gt;&lt;br /&gt;　　And after installed the source, the version number became same as that in the *.deb package.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-8710251213601415627?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/8710251213601415627/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=8710251213601415627&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8710251213601415627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8710251213601415627'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/05/ubuntu-to-mainline-kernel-version.html' title='Ubuntu to Mainline Kernel Version Mapping'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-6405170574110537997</id><published>2010-05-02T20:23:00.006+08:00</published><updated>2011-03-15T16:53:56.131+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Installing Ubuntu 10.04 (2)</title><content type='html'>Some additional words:&lt;br /&gt;&lt;br /&gt;Today, I finally reverted to use pidgin instead of emphathy.&lt;br /&gt;There's a plugin call "musictracker" which displays the "now playing" info.&lt;br /&gt;# sudo apt-get install pidgin-musictracker&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4571001642/"&gt;&lt;img src="http://farm5.static.flickr.com/4054/4571001642_86ef5b4d66.jpg" width="500" height="366" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It seems that nickname cannot be changed when using MSN protocol.&lt;br /&gt;I did set the friendly name, but Others cannot see.&lt;br /&gt;And the personal message is called status in pidgin, so set it there.&lt;br /&gt;&lt;br /&gt;For QQ protocol, using pidgin may cause activation problem.&lt;br /&gt;An error shows to tell you to activate your account via &lt;a href="http://jihuo.qq.com/"&gt;jihuo.qq.com&lt;/a&gt;.&lt;br /&gt;Open the account settings, uncheck the "Connect by TCP" may solve the issue.&lt;br /&gt;&lt;br /&gt;I google a lot to find a plugin for rhythmbox to show lyrics automatically.&lt;br /&gt;Though rhythmbox does have a lyrics plugin, it cannot find most Chinese lyrics.&lt;br /&gt;Then I find &lt;a href="http://forum.ubuntu.org.cn/viewtopic.php?f=74&amp;t=253276&amp;start=0"&gt;LrcShow-X&lt;/a&gt;. It works well.&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4570364265/"&gt;&lt;img src="http://farm4.static.flickr.com/3418/4570364265_462dfea5ed.jpg" width="500" height="395" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-6405170574110537997?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/6405170574110537997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=6405170574110537997&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6405170574110537997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6405170574110537997'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/05/installing-ubuntu-1004-2.html' title='Installing Ubuntu 10.04 (2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4054/4571001642_86ef5b4d66_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-232915826904674705</id><published>2010-04-30T22:25:00.010+08:00</published><updated>2011-10-04T03:07:35.337+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Lucid'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>Installing Ubuntu 10.04</title><content type='html'>Sorry for leaving this blog outdated for so long.&lt;br /&gt;Since go out of &lt;a href="http://en.wikipedia.org/wiki/Golden_Shield_Project"&gt;GFW&lt;/a&gt; is not a so easy task.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;There's something to mention about installation.&lt;br /&gt;&lt;br /&gt;0. installation:&lt;br /&gt;I installed lucid from harddisk.&lt;br /&gt;There's an lock issue when modifying the partition table.&lt;br /&gt;We should umount the iso first:&lt;br /&gt;# sudo umount -l /isodevice&lt;br /&gt;&lt;br /&gt;1. grub&lt;br /&gt;The original grub installation will not probe Windows OSes.&lt;br /&gt;See &lt;a href="https://bugs.launchpad.net/ubuntu/+source/ubiquity/+bug/570765"&gt;here&lt;/a&gt;. So you must do it manually.&lt;br /&gt;# sudo /usr/sbin/grub-mkconfig &amp;gt; /boot/grub/grub.cfg&lt;br /&gt;&lt;br /&gt;2. qterm&lt;br /&gt;The iBus IME issue seems to be fixed in this version.&lt;br /&gt;But the "Home" and "End" key do not work correctly. This is a &lt;a href="http://sourceforge.net/tracker/?func=detail&amp;amp;aid=2951516&amp;amp;group_id=79581&amp;amp;atid=557094"&gt;resolved bug&lt;/a&gt;.&lt;br /&gt;So, change the key type to "linux" may workaround.&lt;br /&gt;&lt;br /&gt;3. emphathy&lt;br /&gt;Pidgin is replaced with emphathy.&lt;br /&gt;Emphathy is not as powerful as pidgin.&lt;br /&gt;But it integrates better with Gnome's notification area.&lt;br /&gt;&lt;br /&gt;4. totem/rhythmbox&lt;br /&gt;These are video/audio players.&lt;br /&gt;Please install essential codecs.&lt;br /&gt;Otherwise, almost nothing could be played and seek function is not available.&lt;br /&gt;# sudo apt-get install gstreamer0.10-plugins-bad gstreamer0.10-plugins-bad-multiverse&lt;br /&gt;# sudo apt-get install gstreamer0.10-plugins-ugly gstreamer0.10-plugins-ugly-multiverse&lt;br /&gt;# sudo apt-get install libavcodec-extra-52 libavutil-extra-49&lt;br /&gt;Now, almost all media formats can be played.&lt;br /&gt;Also, media plugins in firefox works.&lt;br /&gt;&lt;br /&gt;5. fglrx&lt;br /&gt;This is the graphics driver for ATI cards.&lt;br /&gt;You may experience better performance and effects.&lt;br /&gt;But after I installed it, I could not play Warcraft III using wine.&lt;br /&gt;So I reverted to the original default graphics driver, and it works.&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/4565244995/"&gt;&lt;img alt="ubuntu1004_warcraft3" height="375" src="http://farm5.static.flickr.com/4015/4565244995_b44b0b6316.jpg" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;To play other 3D games, make sure your have turned off compiz firstly.&lt;br /&gt;&lt;br /&gt;6. gimp&lt;br /&gt;The gimp is not installed by defaut, so...&lt;br /&gt;&lt;br /&gt;7. acpid&lt;br /&gt;I'm running on a Thinkpad T60 machine.&lt;br /&gt;The brightness function key works correctly, but the volume button does not.&lt;br /&gt;Then I found that the hotkey mask should be enabled:&lt;br /&gt;&lt;a href="http://swiss.ubuntuforums.org/showthread.php?t=1328016"&gt;http://swiss.ubuntuforums.org/showthread.php?t=1328016&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.thinkwiki.org/wiki/thinkpad-acpi"&gt;http://www.thinkwiki.org/wiki/thinkpad-acpi&lt;/a&gt;&lt;br /&gt;After all, I add following line in the startup script, /etc/rc.local:&lt;br /&gt;cp /sys/devices/platform/thinkpad_acpi/hotkey_all_mask /sys/devices/platform/thinkpad_acpi/hotkey_mask&lt;br /&gt;&lt;br /&gt;Then the volume button works. &lt;br /&gt;The play/pause/stop/prev/next buttons also work in rhythmbox.&lt;br /&gt;&lt;br /&gt;8. fstab&lt;br /&gt;I want to mount all windows partitions when boot.&lt;br /&gt;So /etc/fstab file should be edited automatically using pysdm:&lt;br /&gt;# sudo apt-get install pysdm&lt;br /&gt;For ntfs partitions, default option is OK.&lt;br /&gt;For fat32 partitins, add the "utf8=1" string.&lt;br /&gt;Or you may want to edit fstab manually.&lt;br /&gt;You can copy from /etc/mtab file and do some little modification.&lt;br /&gt;For me, the added modified lines are:&lt;br /&gt;&lt;pre&gt;# windows partitions&lt;br /&gt;/dev/sda1 /media/SYSTEM ntfs rw,nosuid,nodev,allow_other,default_permissions 0 0&lt;br /&gt;/dev/sda5 /media/SOFTWARE ntfs rw,nosuid,nodev,allow_other,default_permissions 0 0&lt;br /&gt;/dev/sda6 /media/DATA ntfs rw,nosuid,nodev,allow_other,default_permissions 0 0&lt;br /&gt;/dev/sda7 /media/ENTERTAIN ntfs rw,nosuid,nodev,allow_other,default_permissions 0 0&lt;br /&gt;/dev/sda8 /media/SETUP ntfs rw,nosuid,nodev,allow_other,default_permissions 0 0&lt;br /&gt;/dev/sda9 /media/BACKUP vfat rw,nosuid,nodev,uhelper=udisks,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,flush 0 0&lt;/pre&gt;&lt;br /&gt;9. restricted packages&lt;br /&gt;# sudo apt-get install ubuntu-restricted-extras&lt;br /&gt;This will install some other useful packages.&lt;br /&gt;The open-source java packages are included but not necessary.&lt;br /&gt;Unmark them and install sun's packages instead.&lt;br /&gt;&lt;br /&gt;10. modify reserved space&lt;br /&gt;# sudo tune2fs -m 3 /dev/sda2&lt;br /&gt;&lt;br /&gt;11. ctrl+alt+backspace&lt;br /&gt;See &lt;a href="http://www.ubuntugeek.com/enable-ctrl-alt-backspace-in-ubuntukubuntu-10-04lucid-lynx.html"&gt;here&lt;/a&gt;: &lt;br /&gt;Since Ubuntu 9.04, the Ctrl-Alt-Backspace key combination to force a  restart of X is now disabled by default, to eliminate the problem of  accidentally triggering the key combination. In addition, the  Ctrl-Alt-Backspace option is now configured as an X keymap (XKB) option,  replacing the X server "DontZap" option and allowing per-user  configuration of this setting.&lt;br /&gt;As a result, enabling or disabling the Ctrl+Alt+Backspace shortcut can now be done easily from the desktop.&lt;br /&gt;-- Enabling Ctrl-Alt-Backspace for Ubuntu 10.04&lt;br /&gt;&amp;nbsp; * Select "System" -&amp;gt; "Preferences" -&amp;gt; "Keyboard".&lt;br /&gt;&amp;nbsp; * Select the "Layouts" tab and click on the "Layout Options" button.&lt;br /&gt;&amp;nbsp; * Select "Key sequence to kill the X server" and enable "Control + Alt + Backspace".&lt;br /&gt;-- Enabling Ctrl-Alt-Backspace for Kubuntu 10.04&lt;br /&gt;&amp;nbsp; * Click on the Application launcher and select "System Settings".&lt;br /&gt;&amp;nbsp; * Click on "Regional &amp;amp; Language".&lt;br /&gt;&amp;nbsp; * Select "Keyboard Layout".&lt;br /&gt;&amp;nbsp; * Click on "Enable keyboard layouts" (in the Layout tab).&lt;br /&gt;&amp;nbsp; * Select the "Advanced" tab. Then select "Key sequence to kill the X server" and enable "Control + Alt + Backspace".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-232915826904674705?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/232915826904674705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=232915826904674705&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/232915826904674705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/232915826904674705'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2010/04/installing-ubuntu-1004.html' title='Installing Ubuntu 10.04'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4015/4565244995_b44b0b6316_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-6999078829118530847</id><published>2009-12-31T23:59:00.008+08:00</published><updated>2009-03-09T13:59:25.522+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>[置顶] 2009年</title><content type='html'>1. 工资小涨100%&lt;br /&gt;2. 努力搞好跟家里的关系&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.mozilla.com/"&gt;Firefox&lt;/a&gt; is recommended to view the blog :)&lt;br /&gt;If there's any display issue in other browsers, please let me know via email.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-6999078829118530847?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/6999078829118530847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=6999078829118530847&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6999078829118530847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6999078829118530847'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/02/2009.html' title='[置顶] 2009年'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5116437499142557488</id><published>2009-10-09T14:20:00.002+08:00</published><updated>2011-03-15T16:55:16.714+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><title type='text'>整理了一下Qt 的coding convention</title><content type='html'>　　开门见山, 我就直接罗列了, 主要是naming convention, style convention 的话, 私以为自己还不错, 就不参考了.&lt;br /&gt;&lt;br /&gt;0. General:&lt;br /&gt;a) 命名要有意义.&lt;br /&gt;b) 命名要一致. 比如不要先用prev, 然后用previous.&lt;br /&gt;c) 命名尽量不要缩写. 超过2 个字母, 第一个字母大写其余小写; 只有2 个字母的则全部大写.&lt;br /&gt;&lt;br /&gt;1. Class:&lt;br /&gt;a) 类名: 单词首字母大写, 以Q 为首字母.&lt;br /&gt;b) 成员变量: 除了第一个单词, 其余首字母大写.&lt;br /&gt;c) 成员函数: 同上.&lt;br /&gt;d) 静态成员: 同上.&lt;br /&gt;e) 接口: Qt 似乎除了plugin 相关, 不太用接口(纯抽象类). 一般以QXxxInterface, QXxxPlugin 来命名.&lt;br /&gt;&lt;br /&gt;2. 结构:&lt;br /&gt;a) 命名跟类一样, 没有特别的convention.&lt;br /&gt;b) 公有的结构以Q 为首字母. 如果是嵌套的, 似乎没有规律.&lt;br /&gt;&lt;br /&gt;3. 枚举:&lt;br /&gt;a) 命名跟类一样, 没有特别的convention.&lt;br /&gt;b) 与类相关的枚举可以定义在类中, 这样可以用类名作为前缀.&lt;br /&gt;c) 公有枚举放到公共的名字空间中. 类, 结构, 接口不放到这个名字空间.&lt;br /&gt;d) 命名体现枚举值的相关性. 比如Qt::CaseInsensitive, Qt::CaseSensitive.&lt;br /&gt;e) 尽量用枚举作为Flag 使用. Qt 中有QFlag, QFlags 两个类作为辅助.&lt;br /&gt;&lt;br /&gt;5. 函数:&lt;br /&gt;a) 全局函数: qXxxXxx. 比如qFill, qBinaryFind.&lt;br /&gt;&lt;br /&gt;6. 宏:&lt;br /&gt;a) 全部大写, 下划线分隔.&lt;br /&gt;b) static const 的全局变量同上.&lt;br /&gt;&lt;br /&gt;7. PS:&lt;br /&gt;a) 编辑器的文本编码最好设成ascii, 这样就保证不会出现中文之类了.&lt;br /&gt;b) 函数的参数, Qt 推荐使用指针, 而不是引用, 因为能显式说明参数会被修改.&lt;br /&gt;c) 头文件include 的顺序, 越是specilized 的放在前面, 越是general 的越放在后面.&lt;br /&gt;&lt;br /&gt;　　Qt 的coding convention 跟Java 的非常像. 私以为加上匈牙利命名法会更好一些. 其实又参考了wxWidgets 的部分代码, 由于它不用命名空间, 所以枚举的命名有些小不一样.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;参考:&lt;br /&gt;&lt;a href="http://doc.trolltech.com/qq/qq13-apis.html"&gt;Designing Qt-Style C++ APIs&lt;/a&gt;&lt;br /&gt;&lt;a href="http://qt.gitorious.org/qt/pages/CodingConventions"&gt;Qt - CodingConventions&lt;/a&gt;&lt;br /&gt;&lt;a href="http://qt.gitorious.org/qt/pages/QtCodingStyle"&gt;Qt - CodingStyle&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5116437499142557488?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5116437499142557488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5116437499142557488&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5116437499142557488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5116437499142557488'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/10/qt-coding-convention.html' title='整理了一下Qt 的coding convention'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2885443969658088904</id><published>2009-09-17T14:05:00.002+08:00</published><updated>2011-03-15T16:55:27.798+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Ubuntu'/><title type='text'>某list 备份</title><content type='html'>gcc-3.4&lt;br /&gt;g++-3.4&lt;br /&gt;build-essential&lt;br /&gt;wxwidgets-dev&lt;br /&gt;glib-dev&lt;br /&gt;libgtk2-dev&lt;br /&gt;qt-dev&lt;br /&gt;cairo-dev&lt;br /&gt;patch&lt;br /&gt;cvs&lt;br /&gt;automake&lt;br /&gt;autoconf&lt;br /&gt;doxygen&lt;br /&gt;cmake&lt;br /&gt;bison&lt;br /&gt;flex&lt;br /&gt;xulrunner-dev&lt;br /&gt;libxml2-dev&lt;br /&gt;tcl&lt;br /&gt;tk&lt;br /&gt;vim&lt;br /&gt;java&lt;br /&gt;language-support-fonts-zh&lt;br /&gt;language-support-input-zh&lt;br /&gt;scim-bridge&lt;br /&gt;flash&lt;br /&gt;apache&lt;br /&gt;libapr&lt;br /&gt;libaprutil&lt;br /&gt;ruby&lt;br /&gt;php5&lt;br /&gt;python&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2885443969658088904?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2885443969658088904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2885443969658088904&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2885443969658088904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2885443969658088904'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/09/list.html' title='某list 备份'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1108757547147035286</id><published>2009-09-16T10:54:00.008+08:00</published><updated>2011-03-15T16:55:43.668+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Apache'/><title type='text'>Apache Modules 学习笔记(1)</title><content type='html'>　　　　最近看了这本&amp;lt;&amp;lt;The Apache Modules Book&amp;gt;&amp;gt;: &lt;a href="http://www.amazon.com/gp/product/B000SEGRM8/"&gt;http://www.amazon.com/gp/product/B000SEGRM8/&lt;/a&gt;, 记录一下.&lt;br /&gt;　　　　每次我们学一个新的东西的时候, 似乎都会写一个程序叫做"hello world", 今天的目的也在于此. 看这本书的目的主要是为了了解Apache 的扩展性到底是如何做到的. Apache 主要提供了hook, filter, provider 等机制. 其次, 就是Apache 的跨平台和平台相关的优化. 本人对这些东西的了解还比较粗浅, 本书感觉也只是在大量的贴Apache 的源码, 所以还是要看Apache 的manual. 最后, Apache 的源码确实写的非常有参考价值, 很多东西我都不知道原来能那么用的.&lt;br /&gt;&lt;br /&gt;　　　　好了, 进正题, 我们要写的是一个"hello world" 的generator module. 运行的结果如图:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/3925163160/" title="apache_1_1 by 贡丸, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3161/3925163160_13f2cb7e0d.jpg" alt="apache_1_1" height="338" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;　　　　然后是代码, 有点长:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;#include &amp;lt;httpd.h&amp;gt;&lt;br /&gt;#include &amp;lt;http_protocol.h&amp;gt;&lt;br /&gt;#include &amp;lt;http_config.h&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static int print_item(void* rec, const char* key, const char* value)&lt;br /&gt;{&lt;br /&gt;  /* rec is a user data pointer */&lt;br /&gt;  request_rec* r = rec;&lt;br /&gt;  ap_rprintf(r, "&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;%s&amp;lt;/th&amp;gt;&amp;lt;td&amp;gt;%s&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;",&lt;br /&gt;      ap_escape_html(r-&amp;gt;pool, key), ap_escape_html(r-&amp;gt;pool, value));&lt;br /&gt;  /* 0 would stop iterating, any other return value continues */&lt;br /&gt;  return 1;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void print_table(request_rec* r, apr_table_t* t,&lt;br /&gt;                      const char* keyhead, const char* valhead)&lt;br /&gt;{&lt;br /&gt;  /* table header */&lt;br /&gt;  ap_rputs("&amp;lt;table&amp;gt;", r) ;&lt;br /&gt;  ap_rprintf(r, &lt;br /&gt;      "&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;%s&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;%s&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;", &lt;br /&gt;      keyhead, valhead);&lt;br /&gt;  /* table data */&lt;br /&gt;  ap_rputs("&amp;lt;tbody&amp;gt;", r);&lt;br /&gt;  apr_table_do(print_item, r, t, NULL);&lt;br /&gt;  ap_rputs("&amp;lt;/tbody&amp;gt;", r);&lt;br /&gt;  /* table footer */&lt;br /&gt;  ap_rputs("&amp;lt;/table&amp;gt;", r);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static int helloworld_handler(request_rec* r)&lt;br /&gt;{&lt;br /&gt;  /* r-&amp;gt;handler is specified in configure file */&lt;br /&gt;  if (!r-&amp;gt;handler || strcmp(r-&amp;gt;handler, "helloworld")) {&lt;br /&gt;      return DECLINED;&lt;br /&gt;  }&lt;br /&gt;  if (r-&amp;gt;method_number != M_GET) {&lt;br /&gt;      return HTTP_METHOD_NOT_ALLOWED;&lt;br /&gt;  }&lt;br /&gt;  /* generate html header */&lt;br /&gt;  ap_set_content_type(r, "text/html; charset=ascii");&lt;br /&gt;  ap_rputs("&amp;lt;!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"&amp;gt;", r);&lt;br /&gt;  ap_rputs("&amp;lt;html&amp;gt;", r);&lt;br /&gt;  ap_rputs("&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;Apache HelloWorld Module&amp;lt;/title&amp;gt;&amp;lt;/head&amp;gt;", r);&lt;br /&gt;  ap_rputs("&amp;lt;body&amp;gt;", r);&lt;br /&gt;  ap_rputs("&amp;lt;h1&amp;gt;Hello World!&amp;lt;/h1&amp;gt;", r);&lt;br /&gt;  ap_rputs("&amp;lt;p&amp;gt;This is the Apache HelloWorld module!&amp;lt;/p&amp;gt;", r) ;&lt;br /&gt;  /* print the request headers */&lt;br /&gt;  print_table(r, r-&amp;gt;headers_in, "Header", "Value") ;&lt;br /&gt;  ap_rputs("&amp;lt;/body&amp;gt;", r);&lt;br /&gt;  ap_rputs("&amp;lt;/html&amp;gt;", r);&lt;br /&gt;  return OK;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static void helloworld_hooks(apr_pool_t* pool)&lt;br /&gt;{&lt;br /&gt;  ap_hook_handler(helloworld_handler, NULL, NULL, APR_HOOK_MIDDLE) ;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;module AP_MODULE_DECLARE_DATA helloworld_module =&lt;br /&gt;{&lt;br /&gt;  STANDARD20_MODULE_STUFF,&lt;br /&gt;  NULL,&lt;br /&gt;  NULL,&lt;br /&gt;  NULL,&lt;br /&gt;  NULL,&lt;br /&gt;  NULL,&lt;br /&gt;  helloworld_hooks&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　　　这个module 的用途是打印接受到的request 的header 信息. 需要知道的有两部分: module 的声明, module 的hook 函数. Apache 模块的都是通过"module" 这个struct 来声明导出的, 在这个struct 中会初始化这个模块的各个函数指针. 在我们的代码中, 中间5 个值都是NULL, 它们是用来安装配置文件相关的hook 的, 暂时不用. 最后一个hook 则指向一个相当于运行时的hook 函数, 在这个函数, 即"helloworld_hooks" 中, 我们指定Apache 的那些处理过程会被我们hook 到. 这里我们使用了ap_hook_handler 这个函数, 它表明我们的模块是一个generator handler. 它的参数helloworld_handler 依然是一个函数指针, 表示具体的处理过程. 其它的代码都是html 的生成, 先随便看看吧. &lt;br /&gt;　　　　接下来是编译的问题. 如果用VC 的话, 那么就是简单的把apache, apr, apr-util 的include 和lib 的路径加进去, 基本就通过编译了. 不过有的module 可能会依赖其它module, 个么这个也自己加. 我写了一个简单的Makefile 来编译, 如下:&lt;br /&gt;&lt;pre class="brush: plain"&gt;&lt;br /&gt;APACHE=httpd-2.2.13&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CC          = cl&lt;br /&gt;DEFINESD    = /DWIN32 /D_DEBUG&lt;br /&gt;DEFINES     = /DWIN32&lt;br /&gt;CFLAGSD     = /nologo /ZI /Od /MDd /LDd&lt;br /&gt;CFLAGS      = /nologo /Zi /O2 /MD /LD&lt;br /&gt;INCPATH     = -I$(APACHE)\include  \&lt;br /&gt;        -I$(APACHE)\srclib\apr\include  \&lt;br /&gt;        -I$(APACHE)\srclib\apr-util\include &lt;br /&gt;LINK        = link&lt;br /&gt;LFLAGSD     = /DLL&lt;br /&gt;LFLAGS      = /DLL&lt;br /&gt;LIBSD       = $(APACHE)\Debug\libhttpd.lib  \&lt;br /&gt;        $(APACHE)\srclib\apr\Debug\libapr-1.lib  \&lt;br /&gt;        $(APACHE)\srclib\apr-util\Debug\libaprutil-1.lib&lt;br /&gt;LIBS        = $(APACHE)\Release\libhttpd.lib  \&lt;br /&gt;        $(APACHE)\srclib\apr\Release\libapr-1.lib  \&lt;br /&gt;        $(APACHE)\srclib\apr-util\Release\libaprutil-1.lib&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;debug:&lt;br /&gt;    $(CC) $(DEFINESD) $(CFLAGSD) $(INCPATH) mod_helloworld.c /link $(LFLAGSD) $(LIBSD) /OUT:mod_helloworldd.so&lt;br /&gt;&lt;br /&gt;release:&lt;br /&gt;    $(CC) $(DEFINES) $(CFLAGS) $(INCPATH) mod_helloworld.c /link $(LFLAGS) $(LIBSD) /OUT:mod_helloworld.so&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　　　vs2005, vs2008 皆可通过编译. vs 的-I 选项似乎不支持绝对路径, 所以编译之前请修改$(APACHE) 变量. 另外, 发现一个问题就是, debug 编译的Apache 不能加载release 编译的module. 后来发现是vs2005/2008 的CRT dll的SxS 的问题. 所以, Apache 和module 的编译器最好是同一版本和配置, 这样CRT 才能被正确加载进来. 或者就是静态链接到CRT. &lt;br /&gt;　　　　把编译出来的*.so 文件拷贝到Apache 的modules 文件夹下. 最后来修改配置文件. 打开httpd.conf, 添加如下代码:&lt;br /&gt;&lt;pre class="brush: plain"&gt;&lt;br /&gt;LoadModule helloworld_module modules/mod_helloworld.so&lt;br /&gt;&amp;lt;Location /helloworld&amp;gt;&lt;br /&gt;    SetHandler helloworld&lt;br /&gt;&amp;lt;/Location&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　　　 LoadModule 指令用来加载模块, 第一个参数是在代码中导出(export) 的模块名, 第二个参数是模块的路径. 然后来设置映射关系, 凡是URL 是/helloworld 开头的, 都用helloworld 这个handle 来处理, 而helloworld 这个handle, 实际上只是我们在代码中字符串比较用的, 参见helloworld_handler 这个函数. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;　　　　以上.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1108757547147035286?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1108757547147035286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1108757547147035286&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1108757547147035286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1108757547147035286'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/09/apache-modules-1.html' title='Apache Modules 学习笔记(1)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3161/3925163160_13f2cb7e0d_t.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3891318692270511345</id><published>2009-09-08T13:13:00.008+08:00</published><updated>2011-03-15T16:56:14.211+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='MSVC'/><category scheme='http://www.blogger.com/atom/ns#' term='Apache'/><title type='text'>Building Apache Web Server with Visual Studio 2005</title><content type='html'>1. Source:&lt;br /&gt;　　a) apache 2.2.13: &lt;a href="http://www.apache.org/dist/httpd/httpd-2.2.13-win32-src.zip"&gt;http://www.apache.org/dist/httpd/httpd-2.2.13-win32-src.zip&lt;/a&gt;&lt;br /&gt;　　b) zlib 1.2.3 (for mod_deflate): &lt;a href="http://www.zlib.net/zlib-1.2.3.tar.gz"&gt;http://www.zlib.net/zlib-1.2.3.tar.gz&lt;/a&gt;&lt;br /&gt;　　c) openssl 0.9.8k (for mod_ssl): &lt;a href="http://www.openssl.org/source/openssl-0.9.8k.tar.gz"&gt;http://www.openssl.org/source/openssl-0.9.8k.tar.gz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2. Tools:&lt;br /&gt;　　a) ActivePerl: &lt;a href="http://aspn.activestate.com/ASPN/Downloads/ActivePerl/"&gt;http://aspn.activestate.com/ASPN/Downloads/ActivePerl/&lt;/a&gt;&lt;br /&gt;　　b) awk &amp;amp; patch tools: &lt;a href="http://gnuwin32.sourceforge.net/packages.html"&gt;http://gnuwin32.sourceforge.net/packages.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3. Steps:&lt;br /&gt;　　a) Setup Perl environment, add &lt;code&gt;%Perl%/bin&lt;/code&gt; to &lt;code&gt;%PATH%&lt;/code&gt;.&lt;br /&gt;　　b) Also add awk, path tools to &lt;code&gt;%PATH%&lt;/code&gt;.&lt;br /&gt;　　c) Decompress the apache source code to &lt;code&gt;%Apache%&lt;/code&gt;, &lt;code&gt;D:\Apache&lt;/code&gt; maybe.&lt;br /&gt;　　d) Decompress the zlib into &lt;code&gt;srclib&lt;/code&gt; subdirectory named &lt;code&gt;zlib&lt;/code&gt;.&lt;br /&gt;　　e) Decompress the openssl into &lt;code&gt;srclib&lt;/code&gt; subdirectory named &lt;code&gt;openssl&lt;/code&gt;.&lt;br /&gt;　　f) Now the source tree should look like:&lt;br /&gt;&lt;pre&gt;%Apache%&lt;br /&gt;　　|&lt;br /&gt;　　　+ srclib&lt;br /&gt;　　|   |&lt;br /&gt;　　|   + apr&lt;br /&gt;　　|   |&lt;br /&gt;　　|   + openssl&lt;br /&gt;　　|   |&lt;br /&gt;　　|   + zlib&lt;br /&gt;　　|   |&lt;br /&gt;　　|   + ...&lt;br /&gt;　　|&lt;br /&gt;　　　+ ...&lt;/pre&gt;&lt;br /&gt;　　g)　Patch zlib:&lt;br /&gt;　　Download the patch from: &lt;a href="http://www.apache.org/dist/httpd/binaries/win32/patches_applied/zlib-1.2.3-vc32-2005-rcver.patch"&gt;http://www.apache.org/dist/httpd/binaries/win32/patches_applied/zlib-1.2.3-vc32-2005-rcver.patch&lt;/a&gt;. This patch contains minor fixes and enable generation of *.pdb files.&lt;br /&gt;　　Copy the patch file into &lt;code&gt;zlib&lt;/code&gt; subdirectory, swith to the directory in cmd.exe and run the command:&lt;br /&gt;&lt;pre class="brush: plain"&gt;patch -p0 &amp;lt; zlib-1.2.3-vc32-2005-rcver.patch&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　h) Patch openssl:&lt;br /&gt;　　Download the patch from: &lt;a href="http://www.apache.org/dist/httpd/binaries/win32/patches_applied/openssl-0.9.8k-vc32.patch"&gt;http://www.apache.org/dist/httpd/binaries/win32/patches_applied/openssl-0.9.8k-vc32.patch&lt;/a&gt;. This patch will correct a link issue with zlib and enable generation of *.pdb files.&lt;br /&gt;　　Copy the patch file into &lt;code&gt;openssl&lt;/code&gt; subdirectory, swith to the directory in cmd.exe and run the command:&lt;br /&gt;&lt;pre class="brush: plain"&gt;patch -p0 &amp;lt; openssl-0.9.8k-vc32.patch&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　i) Build zlib:&lt;br /&gt;&lt;pre class="brush: plain"&gt;nmake -f win32\Makefile.msc&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　j) Build openssl:&lt;br /&gt;&lt;pre class="brush: plain"&gt;perl Configure no-rc5 no-idea enable-mdc2 enable-zlib VC-WIN32 -I../zlib -L../zlib&lt;br /&gt;ms\do_masm.bat&lt;br /&gt;nmake -f ms\ntdll.mak&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　k) Patch Apache:&lt;br /&gt;　　There's an issue in the Makefile.win that build Apache in 2.2.13: &lt;a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=47659"&gt;https://issues.apache.org/bugzilla/show_bug.cgi?id=47659&lt;/a&gt;. Download the patch against branch into the %Apache% directory and run the command:&lt;br /&gt;&lt;pre class="brush: plain"&gt;patch -p0 &amp;lt; r799070_branch_makefile_fix.diff&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　l) Build Apache using command line:&lt;br /&gt;　　Now you can buid Apache by:&lt;br /&gt;&lt;pre class="brush: plain"&gt;nmake -f Makefile.win _apache[d|r]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　And install Apache by:&lt;br /&gt;&lt;pre class="brush: plain"&gt;nmake -f Makefile.win install[d|r]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　m) Build Apache using Visual Studio 2005:&lt;br /&gt;　　There's also a flaw in the *.vcproj conversion of *.dsp through Visual Studio 2005. We must run a perl script to fix it first:&lt;br /&gt;&lt;pre class="brush: plain"&gt;perl srclib\apr\build\cvtdsp.pl -2005&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　Now, everything are OK. In Visual Studio 2005, open the Apache.dsw and convert all *.dsp files to *.vcproj files. Then build the project "BuildBin". The project "InstallBin" project will distribute all the project in the Apache solution.&lt;br /&gt;&lt;br /&gt;4. Debugging with Visual Studio 2005:&lt;br /&gt;　　It's quite simple. After build the project "InstallBin", open the property page of the "httpd" project. Switch to "Debugging" tab, change the Command value into your binary of installed directory. Now, add breakpoints, and press F5 to start your tracing or debugging.&lt;br /&gt;&lt;br /&gt;5. Reference:&lt;br /&gt;　　a) &lt;a href="http://httpd.apache.org/docs/2.2/platform/win_compiling.html"&gt;Compiling Apache for Microsoft Windows&lt;/a&gt;&lt;br /&gt;　　b) &lt;a href="http://www.apachelounge.com/viewtopic.php?t=2560"&gt;Apache 2.2.9 command line build with the Windows 2008 SDK&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3891318692270511345?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3891318692270511345/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3891318692270511345&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3891318692270511345'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3891318692270511345'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/09/building-apache-web-server-with-visual.html' title='Building Apache Web Server with Visual Studio 2005'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1141399600815026094</id><published>2009-09-05T23:36:00.004+08:00</published><updated>2011-03-15T16:32:00.573+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>Job Open: gonwan's girlfriend</title><content type='html'>Brief&lt;br /&gt;　　　I'm now working for ASUS Computer Inc. as a senior software engineer. My wage is about 5k - 8k per month. No house nor car is available.&lt;br /&gt;　　　In spare time, I read books. Learning is important. I also watch animes to relax myself. I like singing. My favorite singer is Fish Leong. Every week, I play badminton or do other sports. But I'm not very good at sports, just for fun. "Living with passion" is my motto.&lt;br /&gt;　　　Lastly, I do not have a plan for marriage in recent two years.&lt;br /&gt;&lt;br /&gt;Title&lt;br /&gt;　　　gonwan's girlfriend&lt;br /&gt;&lt;br /&gt;Requirements&lt;br /&gt;　　　·162-172 a must.&lt;br /&gt;　　　·Intelligent, diligent, and with a pleasant personality.&lt;br /&gt;　　　·Being so outgoing that I can trust and always share my thoughts with you.&lt;br /&gt;　　　·No specific zodiac required.&lt;br /&gt;　　　·Good singing skills preferred.&lt;br /&gt;　　　·Good drawing skills a plus.&lt;br /&gt;&lt;br /&gt;Responsibilities&lt;br /&gt;　　　·Just whatever a girlfriend should do.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;　　　I will offer a better life to you, if you get the position.&lt;br /&gt;　　　Please send your resume to "gonwan (at) gmail (dot) com". Be sure to mark the title with "applying for position". Then you will be informed when and where to take an interview session.&lt;br /&gt;　　　Contact me if you are the one.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1141399600815026094?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1141399600815026094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1141399600815026094&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1141399600815026094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1141399600815026094'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/09/job-open-gonwans-girlfriend.html' title='Job Open: gonwan&apos;s girlfriend'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-6600029240559984597</id><published>2009-08-29T11:39:00.003+08:00</published><updated>2011-03-15T16:32:00.573+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>丸之宅记录2009 (砖头篇)</title><content type='html'>　　2008/08 - 2009/07 读过的技术类书籍.&lt;br /&gt;　　基本按照时间序, 至少读完50% 以上, 其中页数以amazon.com 为准.&lt;br /&gt;&lt;br /&gt;·Cross-Platform Development in C++&lt;br /&gt;　　Authors: Syd Logan&lt;br /&gt;　　Pages: 576&lt;br /&gt;　　Difficulty: ★★★&lt;br /&gt;　　Recommended Degree: ★★★&lt;br /&gt;　　Comprehensive Degree: 95%&lt;br /&gt;　　本书的作者是Netscape 的资深工程师, 也就是现在正在弄firefox 这个东西. 本书实质性的内容不多, 但是对于跨平台的开发目前看来还是唯一一本. 书里一开始说, 对于一个跨平台的项目, 便一开始就要各个平台并行开发, 不能丢掉任何一个. 也就是态度决定一切. 接着介绍了一般跨平台开发的编码规范, 哪些语言特性是编译器相关的, 哪些特性是平台相关的, 需要避免使用. 然后便是代码的组织结构, 以及如何自己实现跨平台的接口. 在然后是跨平台的一些开发工具. 最后介绍了wxWidgets 这个开源的跨平台项目, 以及作者自己写的一个跨平台类库. &lt;br /&gt;&lt;br /&gt;·C++ GUI Programming with Qt4, 2E&lt;br /&gt;　　Authors: Jasmin Blanchette, Mark Summerfield&lt;br /&gt;　　Pages: 752&lt;br /&gt;　　Difficulty: ★★★☆&lt;br /&gt;　　Recommended Degree: ★★★★&lt;br /&gt;　　Comprehensive Degree: 90%&lt;br /&gt;　　Qt, 这是一个跨平台的GUI 类库, 当然现在已经不仅仅限于GUI 了. 当初看这本书的原因, 自然是因为前一本看的意犹未尽. 而Qt 的代码, 因为有商业版本的支持, 比wxWidgets 质量高很多(Qt 自4.4 版本以后感觉代码质量有所下降). 可以把Qt 的GUI 库想像成Java 中的swing 库, 因为它们的控件都是用GDI 画出来的. 而可以把wxWidgets 的GUI 库想像成Java 中的awt 库, 它们的控件是调用Windows 的API 来绘制的. 所以你可以把它们分别成为light-weight 和heavy-weight. &lt;br /&gt;　　言归正传, 这本书可以说是一本半官方的文档. 除了前几章介绍了Qt 的整体框架之外, 之后开始便都在讲如何使用类库. Qt 的好处, 除了跨平台以外, 还有客户端代码的简洁, 以及很好的工具支持. 当然, 要知道类库怎么用并不难, 难的是要知道类库到底是如何设计的. 看这本书的时候, 丸子经常写一个很简单的程序, 然后用Visual Studio 单步调式Qt 的源代码. 之后, 在公司项目中对于Qt 设计思想的使用, 让我对Qt 有了更深的理解. &lt;br /&gt;&lt;br /&gt;·An Introduction to Design Patterns in C++ with Qt4&lt;br /&gt;　　Authors: Alan Ezust, Paul Ezust&lt;br /&gt;　　Pages: 656&lt;br /&gt;　　Difficulty: ★★&lt;br /&gt;　　Recommended Degree: ★&lt;br /&gt;　　Comprehensive Degree: 100%&lt;br /&gt;　　乍看之下, 本书的名字很牛啊, 又是Qt, 又是C++, 又是design pattern. 但其实却是入门等级的, 丸子也被书名给骗了. 本书的流程大概就是用Qt 的语法, 教你写程序, 顺便提提design pattern. 真无语. &lt;br /&gt;&lt;br /&gt;·Effective C++, 2E&lt;br /&gt;　　Authors: Scott Meyers&lt;br /&gt;　　Pages: 256&lt;br /&gt;　　Difficulty: ★★★&lt;br /&gt;　　Recommended Degree: ★★★&lt;br /&gt;　　Comprehensive Degree: 95%&lt;br /&gt;　　本书也可以说经典了, 但是丸子却没看过. 书中提了50 条C++ 的编程规范, 让你的code 能更加effective. 当时看的时候, 发现自己几乎都知道, 而且中间有很多的废话, 一般人根本不会那么写代码的. 所以感觉收获并不是很大. 还是推荐另外3 本书比较有难度的书: &amp;lt;&amp;lt;exceptional c++&amp;gt;&amp;gt;, &amp;lt;&amp;lt;more exceptional c++&amp;gt;&amp;gt;, &amp;lt;&amp;lt;c++ object model&amp;gt;&amp;gt;, 保证让你看的醉生梦死.&lt;br /&gt;&lt;br /&gt;·Design Patterns: Elements of Reusable Object-Oriented Software&lt;br /&gt;　　Authors: Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides&lt;br /&gt;　　Pages: 416&lt;br /&gt;　　Difficulty: ★★★★&lt;br /&gt;　　Recommended Degree: ★★★★★&lt;br /&gt;　　Comprehensive Degree: 75%&lt;br /&gt;　　又一本经典, 四人帮的书. &lt;br /&gt;　　本书被丸子誉为程序员的九阳神功, 有了它等之后练太极, 练乾坤大挪移就能事半功倍. &lt;br /&gt;　　本书自然是介绍23 种设计模式. 就语言描述来说, 真的是有些难懂, 但确实是目前来说最定义最完整的. 目前公司training 的一本叫做&amp;lt;&amp;lt;head first: design pattern&amp;gt;&amp;gt; 的书, amazon 上评价也不错, 确实更容易理解, 但是这本书说的显然还是太简单了, 而且举的例子事实上很多会混淆读者的理解.&lt;br /&gt;&lt;br /&gt;·Applying UML and Patterns&lt;br /&gt;　　Authors: Craig Larman&lt;br /&gt;　　Pages: 736&lt;br /&gt;　　Difficulty: ★★★★&lt;br /&gt;　　Recommended Degree: ★★★★&lt;br /&gt;　　Comprehensive Degree: 80%&lt;br /&gt;　　本书其实题目起的不好, 它实际上整个都在讲软件工程的过程控制, 中间突出UML 和Pattern (不只是design pattern, 还有architectural pattern) 的核心作用. 反正看不懂就看吧. 本书在7 月份的分组考试中起到了非常重要的作用. &lt;br /&gt;　　另, 本书让我想到上课时我们可爱滴牛老师=v=. &lt;br /&gt;&lt;br /&gt;·Essential COM&lt;br /&gt;　　Authors: Don Box&lt;br /&gt;　　Pages: 464&lt;br /&gt;　　Difficulty: ★★★★☆&lt;br /&gt;　　Recommended Degree: ★★★&lt;br /&gt;　　Comprehensive Degree: 60%&lt;br /&gt;　　本真是目前来说看的最累的一本. 真不知道M$ 那帮人是怎么设计出那么复杂的COM(Component Object Model) 框架的. 本书破天荒的有两篇前言, 一篇还是COM 的设计者, 说没有人能比Box 先生解释COM 解释的更好了. 事实上, 他解释的我也不怎么能看懂, 而且还严重拖延了我的看书计划. 如果没有严重的自虐倾向, 建议看下面这本书. 本书偏理论, 下面那本偏应用. &lt;br /&gt;　　最后说一下, 为什么要用COM. M$ 的最初设计是为了跨平台, 解决C++ 的二进制兼容型. 当然, 很嘲的是, 横跨的是Windows 平台.&lt;br /&gt;&lt;br /&gt;·Inside COM&lt;br /&gt;　　Authors: Dale Rogerson&lt;br /&gt;　　Pages: 376&lt;br /&gt;　　Difficulty: ★★★☆&lt;br /&gt;　　Recommended Degree: ★★★★&lt;br /&gt;　　Comprehensive Degree: 80%&lt;br /&gt;　　本书跟上一本都是COM 的必看书之一. 我在看了上一本前3 章之后, 来看这本, 一晚上扫了100 多页, 真是心情愉快啊. 很多的例子代码能帮助你更好的理解.&lt;br /&gt;&lt;br /&gt;·Pro C# 2008 and the .NET 3.5 Platform, 4E&lt;br /&gt;　　Authors: Andrew Troelsen&lt;br /&gt;　　Pages: 1370&lt;br /&gt;　　Difficulty: ★★★&lt;br /&gt;　　Recommended Degree: ★★★&lt;br /&gt;　　Comprehensive Degree: 90%&lt;br /&gt;　　公司training 的书, 居然有1000 多页. amazon 上评价不错, 但私以为比较垃圾. 本书把你当作C# 的初学者来对待. 作者还很喜欢用这样的词来开头"simply put, .....", 当我们都是sx. 所以我也就随便看看, 主要看的是C# 3.0, 3.5 的新特性, 比如WPF, WCF, WF, LINQ 等. 而这些新特性本书却写的非常的不详细, 果然是给初学者的书. &lt;br /&gt;　　WPF 确实是比较比较好的设计. 这一点不想多说, 光看有很多开源的模仿WPF 的框架就知道这个设计思路有多好. &lt;br /&gt;　　WCF, WF.. 私以为这两个完全没有必要. WCF 虽然说代码的确比较简单, 但那个配置文件没有Visual Studio 的辅助, 基本是配不来的. WF 感觉就是个半成品, 对于Visual Studio 的依赖性更大. &lt;br /&gt;　　LINQ 的设计思路是把SQL 集成到.NET 的语言级别, 想法很好. 但是平白增加了语言的复杂性. 光为了支持LINQ 特性, .NET 3.5 就增加了好几个关键字, 以及好几个语言特性. 而这些新加的特性除了LINQ 之外, 很少会在其它库中用到. &lt;br /&gt;　　丸子评价可能带有片面性, 请自行判断. &lt;br /&gt;&lt;br /&gt;·Programming Windows, 5E&lt;br /&gt;　　Authors: Charles Petzold&lt;br /&gt;　　Pages: 1100&lt;br /&gt;　　Difficulty: ★★★☆&lt;br /&gt;　　Recommended Degree: ★★★★☆&lt;br /&gt;　　Comprehensive Degree: 90%&lt;br /&gt;　　大师的书啊.. Charles Petzold, 响当当的名字. &lt;br /&gt;　　本书侧重于介绍Windows GUI 的编程. 一个最最简单的Windows 窗口, 完全调用Windows API 的话大概要70-80 行代码. 而*nix/gtk 大概是20 行以内, Qt 和Java 应该能在10 行以内. Windows API 的代码效率实在有待商榷. &lt;br /&gt;　　言归正传, 本书从Windows 的窗口消息机制讲起, 消息循环, 消息分发, 屏幕重绘, 控件的使用, Owner-draw, Hook. 然后本书的另外一个大头讲了GDI 的相关内容, 非常的深入. GDI 的使用是一件让人很头痛的事情, 功能本身不怎么强大, 但非常容易写出memory leak, 或者GDI handle leak 的代码. 于是M$ 之后发布了GDI+, 这个GDI 的扩展版本确实比GDI 强大了不少, 而且是OO 的. 但是缺点是, 绘图那个慢啊.. 而且debug 困难. &lt;br /&gt;　　另外推荐一本&amp;lt;&amp;lt;Programmiong Application for Microsoft Windows&amp;gt;&amp;gt;. 这本测试的是Windows API 的非GUI 部分.&lt;br /&gt;&lt;br /&gt;·Microsoft Windows Internals, 4E&lt;br /&gt;　　Authors: Mark E. Russinovich, David A. Solomon&lt;br /&gt;　　Pages: 976&lt;br /&gt;　　Difficulty: ★★★★☆&lt;br /&gt;　　Recommended Degree: ★★★★☆&lt;br /&gt;　　Comprehensive Degree: 80%&lt;br /&gt;　　本书也是一本牛书, Windows 内核最权威的书, 前Windows 部门的项目经理甚至为它作序. 就书本身来说, 语言方面真的没人能写出那么拗口的句子了, 从句套从句, 有时候一打段文字它居然就只有一句句子. 但没办法, 书就那么一本.&lt;br /&gt;　　如果说上面那本偏重的是user mode 的话, 那么本书偏中的就是kernel mode. M$ 的东西, 它就是不开源. 一个可能很容易的概念, 一旦把它作为黑盒来分析的话, 理解起来就会非常的累人, 不像Linux, 所有的代码你都可以看. 书中推荐使用Windbg 来调试内核. &lt;br /&gt;　　本书跟一般的OS 书一样, 介绍了Windows 的进程, 线程, 内存管理, 缓存, 存储管理, 安全性等一系列的相关的实现及最初的设计思路. 让我发现M$ 确实是很有创造力的一家公司, 很多东西都是在Windows 这个OS 上最先出现的哦, 而且它的设计思路完全不走寻常路=v=. &lt;br /&gt;　　对于本书的理解非常重要. 我一般写程序调用Windows API 的时候, MSDN 上很多时候会说, 某个函数一定要跟另外一个搭配使用, 某个函数一定要传入什么什么参数, 某个函数一定要在什么什么模式下使用. 看完本书之后, 很多东西都能解答了, 也就用不着硬记了. &lt;br /&gt;　　另外要说的一点是, M$ Windows 的API 兼容型的确很好, 上个世纪编译的程序一样能在最新的Windows 7 下运行. 但代价就是, Windows 代码的冗余. 看看Linux 内核的开发, 不用的代码, 基本都是标记为deprecated 之后保留几个版本, 然后就直接删掉的. Mac OSX 做的更绝, OSX 之前的代码完全不能用, 而10.5 版本在原来Carbon API的基础上完全重写了一套Cocoa 的API. 当然要我选, 我一定选的是高效的代码. 但M$ 却不是, 这也是M$ 聪明的地方吧.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-6600029240559984597?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/6600029240559984597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=6600029240559984597&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6600029240559984597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6600029240559984597'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/08/2009.html' title='丸之宅记录2009 (砖头篇)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1523209351612037771</id><published>2009-08-29T10:54:00.006+08:00</published><updated>2011-03-15T16:56:30.935+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><title type='text'>Dynamic Volumns</title><content type='html'>　　In early days of August, I finished reading the book &amp;lt;&amp;lt;windows internals 4e&amp;gt;&amp;gt;: &lt;a href="http://www.amazon.com/Microsoft-Windows-Internals-4th-Server/dp/0735619174"&gt;http://www.amazon.com/Microsoft-Windows-Internals-4th-Server/dp/0735619174&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;　　There's a concept called dynamic volume. The volume type we commonly used are called basic volume. Basic volumes and dynamic volumes differ in ability to extend storage beyond one  physical disk. The basic partitions are confined to one disk and their size is fixed. Dynamic  volumes allow to adjust size and to add more free space either from the same  disk or another physical disk.&lt;br /&gt;&lt;br /&gt;　　I have done some experiment using dynamic volumes. I used VirtualBox for my virtual machine environment, since it can mount multiple disks.&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/3866647036/" title="dynamic_disks_1 by 贡丸, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3545/3866647036_27be962f22.jpg" alt="dynamic_disks_1" height="458" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;　　By default, Windows choose basic volume types for installation. You can convert it manually in "Disk Management" component of MMC.&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/3865862739/" title="dynamic_disks_2 by 贡丸, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3565/3865862739_f9a36e45a1.jpg" alt="dynamic_disks_2" height="356" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;　　Then, you can create dynamic volumes of spanned, striped(RAID-0), mirror(RAID-1) and RAID-5 types. For Windows XP, only spanned and striped types are supported.&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/3865862823/" title="dynamic_disks_3 by 贡丸, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3541/3865862823_3451633e8a.jpg" alt="dynamic_disks_3" height="356" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;　　Here's a screen-shot taken under Windows Server 2003:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/3865862917/" title="dynamic_disks_4 by 贡丸, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3548/3865862917_3745e4816b.jpg" alt="dynamic_disks_4" height="359" width="500" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;　　Finally, here's my colorful disk volumes:&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/49942740@N00/3866647288/" title="dynamic_disks_5 by 贡丸, on Flickr"&gt;&lt;img src="http://farm4.static.flickr.com/3245/3866647288_c51640de2b.jpg" alt="dynamic_disks_5" height="359" width="500" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1523209351612037771?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1523209351612037771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1523209351612037771&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1523209351612037771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1523209351612037771'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/08/dynamic-volumns.html' title='Dynamic Volumns'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3545/3866647036_27be962f22_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2516897481652101111</id><published>2009-08-28T10:50:00.000+08:00</published><updated>2011-03-15T16:32:00.574+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>丸子日记 20090828</title><content type='html'>发信人: gonwan (丸子·记得时常更新blog), 信区: gonwan&lt;br /&gt;标  题: 丸子日记 20090828&lt;br /&gt;发信站: 燕曦BBS (2009年08月29日00:08:35 星期六), 站内&lt;br /&gt;&lt;br /&gt;　　原以为把blog 移到墙外, 说话自由. 但事实上也并没有那么多会被屏蔽的话, 而翻墙又是如此讨厌, 于是结果就是, blog 更新起来非常的麻烦, 而我也有很多事情没有及时记录下来.&lt;br /&gt;&lt;br /&gt;　　6 月底, 惯例的老大谈话. 如果去年, 我还需要弄个琉璃挂坠来给我一些心理暗示的话, 那么今年这个时候, 我已经能比较有把握的来谈谈一些比较重要的事情了. 车到山前并不一定有路, 有路只是因为你很幸运. 更多时候, 路还是走出来的, 当然幸运也很重要. 自认为不是很有自信的人, 所有的自信只是建立在有把握的基础之上而已.&lt;br /&gt;&lt;br /&gt;　　7 月初, 有一次training 之后的所谓考试. 4-5 人组队2 天实现一个简单的p2p 聊天文件共享程序. 这种level 的东西, 用最擅长的工具, 单挑大概最快一下午就能完成. 但却有诸多限制, 有一项是一定要用到一些training 讲的我不熟悉的东西. 而为了保证各组平衡性, 分组是一开始就定了的. 考试那天丸子睡过了头, 导致选group leader 的时候明显底气不足. 但后来的事实证明, 缺了的2h 并不算什么, 软件工程的过程控制优势很快就显现了出来. 而经验也远比学历重要, 研究生也一样要听我的, 所以最后的幕后group leader 是我.&lt;br /&gt;　　2 天很快过去了, 然后说延长1 天. 我们组其实并不需要. 接着是各组的demo 和team leader 们的评分. 作为group leader 来说, 总是有一点私心的. 我的目标并不是把这个程序做的如何如何nb, 界面做的如何如何炫, 我的目标只是要跑通软工的整个流程, 因为这种机会目前来说还是第一次. 目标自然是达到了. 比起其它的组, 我们组是每天最早下班的, 也是最早交付代码和文档的.&lt;br /&gt;　　然后, 很不幸, 最后的评分结果, 我们组是得分最低的. 根据事先的评分标准, 我对比了一下其它组, 发现完全找不到理由. 于是我询问了我的leader. 谈话之间的中心思想就是, 这是各个team leader 讨论的结果, 好的, 等于没说. 于是那天晚上几乎都没睡着, 到底是看开了忍, 还是跟各个leader 沟通一遍, 还是如何. 最后决定不能忍, 我还没有到要忍这种事的地步. 于是第二天, 我发了一封长长的群信, 来说明我对于此次评分的看法. 对于重新评分我是不报希望的, 但我就是要说明自己的看法. 发送之前, 这封信被我润色了好多遍. 我的leader 比较友善, 回了一封跟我几乎一样长的信. 另外一个组的leader 当头就是一顿骂, 说我动不动群信, 评分标准不容置疑. 最终的解决是, 我们的老大找大家个谈了一次话.&lt;br /&gt;&lt;br /&gt;　　8 月, 我越来越感受到, 一种叫做个人魅力的东西. 扮成熟并不一定要戴黑框眼镜, 有亲和力也不一定要经常笑. 某相亲类节目确实很有作用, 让我能对于有限的一些表情, 谈吐, 特征, 便能比较快的判断出此人的性格特点. 当然之前看的心理学也有一些帮助. 以前我以为我的直觉很不错, 现在我更愿意相信这只是自己的判断. 所以我喜欢看故事, 而不是快餐型的条条框框的教条. 而所谓的直觉, 只是不了解自己想法而产生的一种暧昧的叫法罢了. 拿公司的项目来说, 就算不成功, 也要毁在我的手里, 我有的是时间呢. 依照九型人格的判定, 我的性格属于观察者和怀疑论者, 据说对于做决策会非常冷静. 而最近有同事说我很强势, 真是第一次有这种评价呢.&lt;br /&gt;　　右手的戒指依然戴着. 虽然不代表什么了, 但确实能减少一些麻烦, 而且我也没有大方到随随便便把半天工资丢掉的地步. 呐, 跟你在一起的时候, 总是会感觉没有存在感. 有时我甚至不知道要说什么, 怎样说, 做什么, 怎样做. 或许像版面流动栏写的一样： "生活就像音乐, 没有谱, 才能随性吟唱". "憧憬, 是距离理解最远的一种感觉啊"(&lt;&lt;死神&gt;&gt;). 或许真的是要去"奋斗" 那一站绕很大一个圈, 直到找到我的存在感我才能真正安心吧. 但同行也好, 等待也好, 我觉得都不是你啊.&lt;br /&gt;　　版面置底其实一直在动. 从6 行到5 行. 从繁复的标题到简单的几个单词. 底部流动栏也是. KISS, 就像&lt;&lt;死神&gt;&gt; 说的, "要攻击就要砍", 简单道理, 简单生活.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2516897481652101111?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2516897481652101111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2516897481652101111&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2516897481652101111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2516897481652101111'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/08/20090828.html' title='丸子日记 20090828'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-8996977093155247876</id><published>2009-07-28T14:23:00.004+08:00</published><updated>2011-03-15T16:38:35.819+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Google Docs'/><title type='text'>Test Using Google Doc</title><content type='html'>&amp;nbsp;&amp;nbsp;&amp;nbsp; This is a article posted from &lt;a title="google doc" href="http://doc.google.com/" id="o8x6"&gt;google doc&lt;/a&gt;. Just for test. &lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; If you see this blog entry, then you may want to get the full steps of publishing a blog entry from google doc &lt;a title="here" href="http://bavatuesdays.com/publishing-google-docs-to-your-blog/" id="debp"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-8996977093155247876?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/8996977093155247876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=8996977093155247876&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8996977093155247876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/8996977093155247876'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/07/test-using-google-doc.html' title='Test Using Google Doc'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1843978489717526283</id><published>2009-07-08T10:47:00.000+08:00</published><updated>2011-03-15T16:32:00.574+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>丸子日记 20090708</title><content type='html'>发信人: gw (丸子·尽管那寂寞偶尔会让你黯然神伤), 信区: gonwan&lt;br /&gt;标  题: 丸子日记 20090708&lt;br /&gt;发信站: 燕曦BBS (2009年07月08日17:49:38 星期三), 站内&lt;br /&gt;&lt;br /&gt;　　本周到今天一直算考试. 内容是4-5 人组team 写一个基于WPF, WCF 的聊天程序.&lt;br /&gt;&lt;br /&gt;　　非常的不幸, 周一直接就睡过了头. 到公司10 点半了, 以至于选leader 的时候明显的底气不足.&lt;br /&gt;　　事实证明, 完全不用这样. 所有的事情完全握在自己的手里最放心. 索性的是我们的leader 还是比较听话的. 所有的mileston, architecture 几乎都是我来定的. 第一次发现所学的软工有了实际的用处. 谁分配做什么, 先做什么后做什么, 到了mileston 没完成怎么办, 这些都是问题. 毕竟第一次领导一整个项目, 而且时间只有2 天(虽然最后延长到了3 天).&lt;br /&gt;　　最后一共分了3 个team. 其实对于这种竞争性的考试来说, 不自觉的就会陷入了所谓的囚徒困境. A 组看到B 组界面很炫, 于是下苦工改界面. B 组看到C 组支持某项高级功能, 于是花时间加新功能. 结果就是第2 天的时候, 其它2 组都没完成, 只有我们组是能跑的, 虽然还有bug. 无奈, 考试还是延长了一天.&lt;br /&gt;　　每天都很兴奋. 某个大牛还曾经为了自己的技术能改变人们的生活兴奋不已呢. 我显然没那么崇高. 我所关心的是, 整个项目都在按照自己的设想有条不紊的发展. &lt;&lt;大剑&gt;&gt; 有大概这样一句: 妖力的极限, 都是在以往不断的战斗中一点一点总结出来的. 我也这么想.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1843978489717526283?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1843978489717526283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1843978489717526283&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1843978489717526283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1843978489717526283'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/07/20090708.html' title='丸子日记 20090708'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3388876186764131763</id><published>2009-06-28T15:12:00.009+08:00</published><updated>2011-03-15T16:57:04.545+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='GDI'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><title type='text'>笔记 - Programming Windows (2)</title><content type='html'>今天来记录一下windows 中GDI (Graphics Device Interface) 的相关内容.&lt;br /&gt;&lt;br /&gt;GDI 的目标是提供一种设备无关的绘图方式, 要支持不同的monitor 和graphics card.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. WM_PAINT 消息: &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;我们还是以以下的window procedure 代码为例:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)&lt;br /&gt;{&lt;br /&gt;    HDC         hdc;&lt;br /&gt;    PAINTSTRUCT ps;&lt;br /&gt;    RECT        rect;&lt;br /&gt;&lt;br /&gt;    switch (message)&lt;br /&gt;    {&lt;br /&gt;    case WM_CREATE:&lt;br /&gt;        PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);&lt;br /&gt;        return 0;&lt;br /&gt;    case WM_PAINT:&lt;br /&gt;        hdc = BeginPaint(hwnd, &amp;amp;ps);&lt;br /&gt;        GetClientRect(hwnd, &amp;amp;rect);&lt;br /&gt;        DrawText(hdc, TEXT("Hello, Windows !!!"), -1, &amp;amp;rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);&lt;br /&gt;        EndPaint(hwnd, &amp;amp;ps);&lt;br /&gt;        return 0;&lt;br /&gt;    case WM_DESTROY:&lt;br /&gt;        PostQuitMessage(0);&lt;br /&gt;        return 0 ;&lt;br /&gt;    }&lt;br /&gt;    return DefWindowProc(hwnd, message, wParam, lParam);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;这次关注的让然是WM_PAINT 消息的处理. 首先我们调用BeginPaint() 函数返回一个HDC 的handle. DC(Device Context) 可以理解成跟设备联系起来的, 可以在上面绘图的一个东西. 这里的设备一般指的是monitor, 但是也可以是printer. 得到这个handle 之后, 我们就可以在DC 上绘图了, DrawText() 函数就在HC 的正中间画了一个字符串. 最后就是EndPaint() 函数来说明绘图结束. 这里有2 个概念.&lt;br /&gt;第一个概念叫做invalid region. 当一个被遮盖的窗口被重新显示的时候, 实际上要重画的只是被遮盖的部分. 而这些被遮盖的需要重画的部分就叫做invalid region. windows 会给窗口发WM_PAINT 消息来让窗口重画. 在代码中ps 变量(PAINTSTRUCT 结构)的rcPaint 域实际上包含了这个invalid region 的信息. 当我们调用BeginPaint() 的时候,实际上把这个invalid region 给validate 了. 不然的话, windows 检测到还有invalid region 没被重画就会不断的发送WM_PAINT 消息, CPU 会100% 的.&lt;br /&gt;第二个概念叫做clipping region. 当我们调用BeginPaint() 的时候, 实际还把一个invalid region 转换成了一个clipping region. 什么意思呢? 就是之后的GDI 调用的绘图都会只限于这个clipping region 中. 如果某个GDI 调用画在了这个clipping region之外, 实际是不会有调用开销的, 这也是windows GDI 的一个优化. 虽然我觉得GDI 还是很慢的=v= (GDI+ 更慢...).&lt;br /&gt;除了调用BeginPaint(), EndPaint() 来得到DC 外, 还可以通过调用GetDC() 这个API. 比如在处理一个鼠标消息, 可能需要在屏幕上画点什么的时候. 不过有这样几点需要注意: 1) BeginPaint(), EndPaint() 只能被用在WM_PAINT 消息中. 2) GetDC() 不会去把invalid region 给validate, 我们需要手动调用ValidateRect() 或ValidateRgn() 这2 个API. 完了之后, 记得调用ReleaseDC().&lt;br /&gt;有的时候, 我们需要手动刷新一个window. 也有两种方法: 1) 调用InvalidateRect() 函数. 这种方法是post 一个WM_PAINT 消息到当前window 的message queue 中, 等待刷新. 一个message queue 中不会出现多个WM_PAINT 消息, windows 会自动合并. 2) 调用UpdateWindow() 函数来强制刷新window, 相当于send 一个WM_PAINT 消息来直接调用window procedure 中的处理代码.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. GDI Objects： &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;现在来看一下DC 的使用. 一个DC 可以有很多的属性. 有以下5 种: Bitmap, Brush, Font, Pen, Region. Bitmap 可以理解成DC 中的画布(canvas), 所有画在DC 上的元素实际都是画在Bitmap 这个属性中的. Brush 表示的是绘图的背景属性, 可以是单色, 渐变色, 或是一个图案(pattern). Font 自然是字体, 包括大小, 颜色, 粗细等. Pen 表示的是画笔的属性, 包括颜色, 粗细, 线段起始点, 拐点的一些绘画属性. Region 表示一个区域, 可以理解为Bitmap 这个canvas 上的一个clipping region.&lt;br /&gt;我们通过SelectObject() 这个API 来设置这些属性. 以Brush 为例, 可以使用系统与定义的Brush:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;SelectObject(hdc, GetStockObject (WHITE_PEN));&lt;/pre&gt;&lt;br /&gt;也可以使用自定义的Brush:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;HBRUSH hbrhRed = CreateSolidBrush(RGB(255, 0, 0));&lt;br /&gt;HBRUSH hbrhOrig = SelectObject(hdc, hbrhRed);&lt;br /&gt;// Do some drawing with the read brush here...&lt;br /&gt;DeleteObject(SelectObject(hdc, hbrhOrig));&lt;/pre&gt;&lt;br /&gt;其它4 种属性的调用相似. 只是最后自定义的属性, 使用完了一定要记得调用DeleteObject() 这个API 来删除, GDI 的object 也是会泄漏(leak) 的.&lt;br /&gt;另外, 有一个logic object 的概念. 当我们调用CreateXXX() 函数的时候, 得到的GDI object 实际已经跟特定的DC 相关联了, 但是有时候, 我们并不要实际的GDI object, 而只是需要一个包含这些信息的一个数据结构. 于是我们就可以使用所谓的logic object. 以Font 为例. 在GDI 中CreateFont() 这个API 可以说是最麻烦的一个API 了, 光参数就有14 个. 相应的, 还有另外一个API 叫做CreateFontIndirect(), 它的参数是一个LOGFONT 结构, 其中的域对应了CreateFont() 的14 个参数, 所以可以用这两个API 完成同样的工作. 其它四种GDI object 也有类似的logic object.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. GDI 坐标映射: &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;到目前为止, 我们并没有设置过GDI 中的任何坐标. 所以我们到底是在用什么单位(unit) 来绘图的呢? 在GDI 中, 默认的坐标映射模式是MM_TEXT. 需要指出的是, 我们在GDI 函数中传入的数字都是逻辑坐标(logic coordinates), 而GDI 会根据当前的映射模式来重新加算设备相关的视点坐标(viewport coordinates).&lt;br /&gt;其它的映射模式包括: MM_LOMETRIC, MM_HIMETRIC, MM_LOENGLISH, MM_HIENGLISH, MM_TWIPS, MM_ISOTROPIC, MM_ANISOTROPIC. 前5 个映射模式只是逻辑坐标的不同, 而x 轴和y 轴坐标都是等比例映射缩放的, 后两种映射模式允许非等比例的坐标映射. 具体的映射规则请查阅MSDN, 因为非常非常的麻烦, 丸子只给出一个映射的计算公式, 其中(xWinOrg, yWinOrg) 是逻辑坐标的原点, (xViewOrg, yViewOrg) 是视点坐标的原点:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;xViewport = (xWindow - xWinOrg) * xViewExt/xWinExt + xViewOrg&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;yViewport = (yWindow - yWinOrg) * yViewExt/yWinExt + yViewOrg&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;这些数值当然不需要手动计算, GDI 主要提供了这样5 个函数来进行坐标映射的操作: SetMapMode(), SetWindowOrgEx(), SettWindowExtEx(), SetViewportOrgEx(), SetViewportExtEx(). &lt;br /&gt;根据丸子的经验, 为了计算坐标更容易, 一般只需要调用SetViewportOrgEx() 来设置视点坐标就可以了, 其它API 函数基本可以不用的.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. DIB 和DDB: &lt;/b&gt;&lt;br /&gt;DIB(Device-Independent Bitmap) 设备独立的位图, DDB(Device-Dependent Bitmap) 设备相关的位图.&lt;br /&gt;什么意思呢? 简单来说, DIB 就是存在硬盘上的bitmap 文件, DDB 就是要在一个DC 上画bitmap 的时候, 一个HBITMAP 的handle 在windows 内存中表示的bitmap. 这里有个很搞笑的事情就是: windows 的GDI 函数中, 并没有提供从文件中读取DIB 的API 函数(Gdiplus 中有), 于是我们要手动写把DIB 转换成DDB 的函数, 这就需要我们了解DIB 的文件结构.&lt;br /&gt;bitmap, 位图, 就是把一张图的所有颜色信息按照pixel 来存储, 所以我们可以把一个DIB 读到内存中, 并把这些按pixel 存储的信息放在一个数组中. 注意, 这里不仅仅是bmp 图片, jpg, png 等其它图片格式, 如果要画到GDI 的DC 上, 都要经过这写操作步骤. 这些步骤搞定之后, 我们可以调用SetDIBitsToDevice() 函数来把这些数组中的信息画到一个DC 上去, 注意倒数第二个参数:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;int SetDIBitsToDevice(&lt;br /&gt;   HDC hdc,                 // handle to DC&lt;br /&gt;   int XDest,               // x-coord of destination upper-left corner&lt;br /&gt;   int YDest,               // y-coord of destination upper-left corner&lt;br /&gt;   DWORD dwWidth,           // source rectangle width&lt;br /&gt;   DWORD dwHeight,          // source rectangle height&lt;br /&gt;   int XSrc,                // x-coord of source lower-left corner&lt;br /&gt;   int YSrc,                // y-coord of source lower-left corner&lt;br /&gt;   UINT uStartScan,         // first scan line in array&lt;br /&gt;   UINT cScanLines,         // number of scan lines&lt;br /&gt;   CONST VOID *lpvBits,     // array of DIB bits&lt;br /&gt;   CONST BITMAPINFO *lpbmi, // bitmap information&lt;br /&gt;   UINT fuColorUse          // RGB or palette indexes&lt;br /&gt;);&lt;/pre&gt;&lt;br /&gt;调用SetDIBitsToDevice() 只是画DIB 的一种方法, 第二种是把一个DIB 转换成一个DDB, 然后就可以调用windows 的Bitblt() 函数来更高效的绘制bitmap 了. 之所以说更高效, 是因为SetDIBitsToDevice() 是一个一个pixel 画的, 而DDB 是已经包含跟DC 相关的bitmap 信息的了. 可以调用CreateDIBitmap() 函数来生产一个DDB, 嗯.. 你没看错, 名字和用处居然不一致. 然而这种方法的缺点是, 不能按pixel 来访问bitmap 的信息了.&lt;br /&gt;于是, 我们有第三种方法, 调用CreateDIBSection() 函数. 这个函数既能转换DIB 到DDB, 又能提供按pixel 访问bitmap 信息的方法. 缺点是, 很难用, 这个API 函数返回的虽然是一个HBITMAP 的handle, 但是跟CreateDIBitmap() 返回的handle 不一样, 有诸多需要特别注意的地方. 所以丸子也不推荐使用= =.&lt;br /&gt;总结一下就是, 对于一张不大的bitmap, 且要精心按pixel 操作的话, 使用SetDIBitsToDevice(). 对于比较大的bitmap, 且要被画多次, 那么使用CreateDIBitmap(), 因为DDB 的绘制会比较快速. 当然, CreateDIBSection() 提供了前两者的好处, 问题就是比较难用.&lt;br /&gt;&lt;br /&gt;以上.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3388876186764131763?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3388876186764131763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3388876186764131763&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3388876186764131763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3388876186764131763'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/programming-windows-2.html' title='笔记 - Programming Windows (2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-7613087728619740251</id><published>2009-06-26T19:25:00.006+08:00</published><updated>2011-03-15T17:05:47.818+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='Unicode'/><title type='text'>笔记 - Programming Windows (1)</title><content type='html'>我终于读完了Charles Petzold 的这本圣书: &lt;a href="http://www.amazon.com/Programming-Windows%C2%AE-Fifth-Microsoft/dp/157231995X"&gt;http://www.amazon.com/Programming-Windows%C2%AE-Fifth-Microsoft/dp/157231995X&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;丸子觉得这本书虽然很多东西已经有些过时了, 比如palette, mci 之类的, 但是有2 个方面讲的非常的深入: 一个是windows 的message 机制, 还有一个是GDI 的绘图部分. 今天闲来讲一下windows 的message 机制.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. 入口函数:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;先看一段最最最入门的代码, 这边写的代码都是纯C 代码:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)&lt;br /&gt;{&lt;br /&gt;MessageBoxA(NULL, "Hello World !", "Hello", MB_OK) ;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;跟console 的程序不同, windows 的窗口程序都是以WinMain 函数作为入口的. 不过这只是一个编译选项而已, 可以指定/entry 参数重设, 当然我们一般都用默认的. 第一个参数hInstance 表示的是这个程序实例的句柄(handle), 我们可以用它来load 内嵌的resource, 第二个参数在win98 以后的版本都不会用到不讲. 第三个参数是传入的命令行参数. 第四个也是运行参数, 控制的是窗口初始化时的现实模式, 最大化, 最小化还是其它什么, 这个参数可以在windows shortcut 的property 里设置, 也可以在CreateProcess() 和ShellExecute() 等API 函数里指定.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Unicode 编码:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;接下来是一个Unicode 的问题, 上面的代码用到的其实是ANSI 编码的API, 从windows nt 开始, Unicode 已经是windows 的内建编码了, 所以Unicode 版本的程序在windows nt 之后的版本会运行的更快一些. 然而windows nt 之前的os 就不一定能运行了. 还是看代码:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR szCmdLine, int iCmdShow)&lt;br /&gt;{&lt;br /&gt;MessageBoxW(NULL, L"Hello World !", L"Hello", MB_OK) ;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;区别有这样几个: WinMain--&amp;gt;wWinMain, PSTR--&amp;gt;PWSTR, MessageBoxA--&amp;gt;MessageBoxW, "Hello"--&amp;gt;L"Hello". 其实就是把函数改成Unicode 版本, 字符串改成宽字符. 我们也可以写一个ANSI 和Unicode 通用的版本:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PTSTR szCmdLine, int iCmdShow)&lt;br /&gt;{&lt;br /&gt;MessageBox(NULL, TEXT("Hello World !"), TEXT("Hello"), MB_OK) ;&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;_tWinMain 实际上是一个宏定义(macro)(注意下划线), 它会根据编译器是否定义了UNICODE 这个宏来分别预处理(preprocess) 成WinMain 和wWinMain, 同样的情况适用于PTSTR, TEXT, MessageBox 宏. 嗯.. 你没看错, MessageBox 实际是一个宏, 具体参阅windows sdk 的头文件.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Windows 消息机制&lt;/b&gt;：&lt;br /&gt;&lt;br /&gt;接下来看一个稍微复杂一些的代码:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);&lt;br /&gt;&lt;br /&gt;int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PTSTR szCmdLine, int iCmdShow)&lt;br /&gt;{&lt;br /&gt;static TCHAR szAppName[] = TEXT("HelloWin");&lt;br /&gt;HWND         hwnd;&lt;br /&gt;MSG          msg;&lt;br /&gt;WNDCLASS     wndclass;&lt;br /&gt;&lt;br /&gt;wndclass.style         = CS_HREDRAW | CS_VREDRAW;&lt;br /&gt;wndclass.lpfnWndProc   = WndProc;&lt;br /&gt;wndclass.cbClsExtra    = 0;&lt;br /&gt;wndclass.cbWndExtra    = 0;&lt;br /&gt;wndclass.hInstance     = hInstance;&lt;br /&gt;wndclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION) ;&lt;br /&gt;wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW) ;&lt;br /&gt;wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH) ;&lt;br /&gt;wndclass.lpszMenuName  = NULL;&lt;br /&gt;wndclass.lpszClassName = szAppName;&lt;br /&gt;&lt;br /&gt;if (!RegisterClass(&amp;amp;wndclass))&lt;br /&gt;{&lt;br /&gt;MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;hwnd = CreateWindow(szAppName,  // window class name&lt;br /&gt;TEXT("Hello"),              // window caption&lt;br /&gt;WS_OVERLAPPEDWINDOW,        // window style&lt;br /&gt;CW_USEDEFAULT,              // initial x position&lt;br /&gt;CW_USEDEFAULT,              // initial y position&lt;br /&gt;CW_USEDEFAULT,              // initial x size&lt;br /&gt;CW_USEDEFAULT,              // initial y size&lt;br /&gt;NULL,                       // parent window handle&lt;br /&gt;NULL,                       // window menu handle&lt;br /&gt;hInstance,                  // program instance handle&lt;br /&gt;NULL);                      // creation parameters&lt;br /&gt;&lt;br /&gt;ShowWindow(hwnd, iCmdShow);&lt;br /&gt;UpdateWindow(hwnd);&lt;br /&gt;&lt;br /&gt;while(GetMessage(&amp;amp;msg, NULL, 0, 0))&lt;br /&gt;{&lt;br /&gt;TranslateMessage(&amp;amp;msg);&lt;br /&gt;DispatchMessage(&amp;amp;msg);&lt;br /&gt;}&lt;br /&gt;return msg.wParam;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)&lt;br /&gt;{&lt;br /&gt;HDC         hdc;&lt;br /&gt;PAINTSTRUCT ps;&lt;br /&gt;RECT        rect;&lt;br /&gt;&lt;br /&gt;switch (message)&lt;br /&gt;{&lt;br /&gt;case WM_CREATE:&lt;br /&gt;PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);&lt;br /&gt;return 0;&lt;br /&gt;case WM_PAINT:&lt;br /&gt;hdc = BeginPaint(hwnd, &amp;amp;ps);&lt;br /&gt;GetClientRect(hwnd, &amp;amp;rect);&lt;br /&gt;DrawText(hdc, TEXT("Hello, Windows !!!"), -1, &amp;amp;rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);&lt;br /&gt;EndPaint(hwnd, &amp;amp;ps);&lt;br /&gt;return 0;&lt;br /&gt;case WM_DESTROY:&lt;br /&gt;PostQuitMessage(0);&lt;br /&gt;return 0;&lt;br /&gt;}&lt;br /&gt;return DefWindowProc(hwnd, message, wParam, lParam) ;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;好长好长的代码呀.. 运行的效果是, 现实一个窗口, 中间有一行字, 启动时还有音效.&lt;br /&gt;我们要显示一个window(指的是程序窗口), 大概要做两件事, 第一是注册这个window 的class, 第二是用这个class 来create 这个window. 分别对应的API 就是RegisterClass() 和CreateWindow().&lt;br /&gt;调用RegisterClass() 的时候, 我们指定这个class 的名字, 样式(style), 实例句柄(instance handle), 以及最最重要的window procedure 的回调函数(callback function)地址, 我们将通过这个回调函数来处理对于属于这个window class 所创建出的window 的消息处理.&lt;br /&gt;RegisterClass() 并不创建实际的window, 而只是创建了一个window 的类别, 比如button 就是一个windows 内建的window class. 我们调用CreateWindow() 来创建一个具体的可现实的window. 可以看到, 这个API 的参数里有一个叫做window style, 这个东西很容易跟之前的class style 搞混. 怎么区分呢? 记住class style 指定的是所有这个class 的window 都会有的style, 比如一个button, 它总是可以click 的, 这就是一个class style. 而window style 则是在class style 的基础上各个window 定制的style, 比如不同的button 可以有不同的观感(look and feel), 这就是要给window style).&lt;br /&gt;&lt;br /&gt;之后, 终于讲到windows 的message 机制了. 每个windows 的程序都会有一个message queue(消息队列), 这个queue 保存了从windows 系统或是其它程序发给这个程序的各种message. windows 可以通过这种方法来实现各个应用程序之间的交互. 有了这个message queue 之后, windows 又定义了叫做message loop(消息循环) 的机制来从这个queue 里拿出消息并进行处理. GetMessage() 这个API 就是用来实现这个功能的, 而代码中GetMessage() 之外的while 循环就叫做message loop.&lt;br /&gt;注意, 这边GetMessage() 拿到的message 是针对整个程序来说的, 并不针对某个特别的窗口. 当GetMessage() 收到的是WM_QUIT 消息的时候返回0, 发生错误的时候返回-1, 其它情况下返回其它非0 值. 所以在代码中我们根据它的返回值是否为0 来判断要不要结束message loop. 在GetMessage() 的输出参数中, 会返回得到的message 数据, 即一个MSG 结构. 在message loop 中, 又有2 个API 调用.&lt;br /&gt;TranslateMessage() 的作用是用来转换键盘消息. 当我们按下一个键的时候, 会产生WM_KEYDOWN 或WM_SYSKEYDOWN 消息, 放开按键的时候则会产生WM_KEYUP 或WM_SYSKEYUP 消息. WM_SYS 开头的消息是系统消息, 一般是Alt 跟其它键的组合键, 比如Alt+Tab, 这个没什么值得讨论的. 在WM_KEYDOWN 的时候, 我们有时要根据shift 是否也被按了来进行大小写字母的判断, 但这不是很好的做法. 比如, caps lock 的状态怎么判断? 如果输入的是中文呢(中文没有对应的virtual key code)? 所以TranslageMessage() 这个API 会帮我们做把所谓keystroke message 转换成character message, 即如果接受到WM_KEYDOWN 消息且shift 被按下又能够组合成一个字符(character), 那么另外一个WM_CHAR 消息会被插入到当前的message queue 中, 紧接在WM_KEYDOWN 消息之后. windows 在处理键盘消息的时候, 其实有一个system message queue. 为什么要有这个东西, 而不把每次的按键直接加到当前窗口的message queue 里呢? 因为无法判断下一个键盘消息到底要发给哪个窗口. 比如要是按了Alt+Tab 怎么办呢?&lt;br /&gt;然后是DispatchMessage() 这个API. 它的作用是把得到的message 传回给windows 系统, 让windows 根据MSG 结构里的信息, 把这个消息dispatch 到相应的window procedure(关于window procedure 之后会讲). 这里其实很神奇, 在我们自己的程序里, 居然要手动dispatch 系统的消息.&lt;br /&gt;&lt;br /&gt;接下来来看window procedure 的回调函数WndProc. 这个函数提供了对于各种发送给窗口的对于处理方法. 这个回调函数有4 个参数: 第一个参数是一个HWND 的handle, 由于多个的window 可以指定同一个window procedure, 可以用这个handle 来区分. 第二个参数是收到的message 的类型. 第三第四个参数是对于当前收到message 的参数, 比如对于WM_KEYDOWN 消息, wParam 就是key 的virtual code, lParam 则是其它一切附加信息. 代码中我们处理了3 个消息: WM_CREATE 是window 在被创建时收到的消息, 我们播放了一段音频. WM_PAINT 是window 要被重画时收到的消息, 我们简单画了一个字符串(关于GDI 相关的内容, 下次笔记再讲). WM_DESTROY 消息则是window 被销毁的时候收到的消息, 我们让整个程序退出. 对于其它我们不感兴趣的消息, 我们简单的把它们扔给DefWindowProc() 来做默认处理.&lt;br /&gt;现在应该对windows 的消息机制有一定了解了, 让我们来看看以上程序中, 当我们按了Alt+F4 的系统热键发生了些什么吧. 我们的WinProc 首先会有到一个WM_SYSCOMMAND 消息, 并传给DefWindowProc() 处理. DefWindowProc() 的默认处理方法就是发一个WM_CLOSE 消息给这个window. 又一次, 我们的WinProc 吧这个消息传给DefWindowProc(). DefWindowProc() 的默认处理方法是调用DestoryWindow(), 而DestroyWindow() 会给这个window 发一个WM_DESTROY 消息. 这次终于有自定义处理代码了, PostQuitMessage() 简单的发送一个WM_QUIT 消息给当前的程序. WM_QUIT 消息导致message loop 的退出(GetMessage() 返回0), 于是整个程序结束. PostQuitMessage() 的参数表示exit code, 会被存在MSG 结构的wParam 域里.&lt;br /&gt;&lt;br /&gt;以上说了message loop 中的消息处理. 这里消息叫做queued message, 但是还有一类叫做nonqueued message, 即它们是不会进入message loop, 而是直接通过上面的window procedure 函数调用的. 有两个函数: SendMessage() 和PostMessage(), 它们分别对应queued 和nonqueued. 调用SendMessage() 产生一个nonqueued message, 结果就是直接调用window procedure 函数, 且函数返回了, SendMessage() 才会返回, 它是同步的. 调用PostMessage() 产生一个queued message, 并把这个message 加到message queue 中, 之后通过程序的GetMessage() 来polling 处理, PostMessage() 是直接返回的, 不需要等到message 被处理完, 它是异步的. 一般, 通过windows API 间接发送的消息都是nonqueued message, 比如代码中的UpdateWindow() 会把WM_PAINT 作为参数直接调用window procedure 回调函数来强制刷新.&lt;br /&gt;另外要提到作为timer 使用的WM_TIMER 消息. 这是一个queued message, 虽然用来计时, 但却不是那么的准确. 如果WM_TIMER 的前一次消息处理时间太长的话, 会把多个WM_TIMER 合并在一起. 因此, 需要更加准确的计时的话, 我们需要调用Thread 的相关API 函数.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. 子控件相关:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;稍微加少下子控件的概念, 所谓的子控件, 就是window上的控件, 真废话=v=.  这里要说的其实没多少东西, 只是一笔带过.&lt;br /&gt;当子控件被点击的时候, 子控件就会给父控件发送一个WM_COMMAND 消息. 当一个push button 被点击, radio button 被选中, check button 被选中都是这个消息. 注意, 是从子控件发送给父控件, 也就是说WM_COMMAND 消息的处理是在父控件的window procedure 回调函数中.&lt;br /&gt;当我们用CreateWindow() 创建window 的时候, 上面的子控件是不具备Tab 遍历功能的, 我们添加对于Tab 键的处理. 但是如果它是通过CreateDialog() 或DialogBox() API 函数创建的话, 只要子控件指定了WS_TABSTOP 的window style 的flag, 就会自动添加Tab 键的遍历功能.&lt;br /&gt;当我们要拿子控件的属性的时候, 我们其实也是通过windows 的message 来实现的. MFC 类库中把这些message 都封装成了宏(macro) 来方便使用. 比如我们要那一个check button 的选中状态, 则可以发送一个BM_GETCHECK 消息.&lt;br /&gt;关于子控件的自定义有3 种方法或者说概念, 从最简单的说起:&lt;br /&gt;a) Owner Draw:&lt;br /&gt;这种方法一般用来定制子控件的外观. 举个例子, 如果要owner-draw 一个push button 的外观, 那么这个button 的style 里要有BS_OWNERDRAW 这个flag. window procedure 回调函数遇到owner-draw 的控件时, 会收到一个WM_DRAWITEM 的消息, 你要做的就是在这个消息处理中把button 画出来.&lt;br /&gt;b) Sub-classing:&lt;br /&gt;这种方法一般用来定制子控件的行为. 还是以push button 为例, button 的点击的默认行为是发送一个WM_COMMAND 消息给父窗口, 那么我们怎么修改这个默认行为呢? 由于button 这类系统与定义的控件的window procedure 都是在windows 系统中写死的, 我们只能想办法替换这个window procedure 回调函数. 具体的方法是调用SetWindowLong() 这个API, 并传入DWL_DLGPROC 这个flag.&lt;br /&gt;c) Custom Control:&lt;br /&gt;不用说了, 最全面的方法. 如果你要完全定义一个全新的子控件. 你需要完全自己coding 所有的代码, 调用RegisterClass(), CreateWindow(), 实现window procedure 回调函数. 很大的工程那...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5. Dialog 对话框:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Dialog 可以分成2 类, modal 和modeless(注意拼写=v=). 具体概念我就不解释了.&lt;br /&gt;一个modal 的dialog 调用DialogBox() 函数创建, 一个modeless 的dialog 调用CreateDialog() 创建. 跟CreateWindow() 的调用一样, 我们也要把一个所谓的dialog procedure 当作参数传进去. 一下是这个procedure 的signature:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;对比window procedure:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;dialog precedure 虽然返回值是一个INT_PTR类型, 但通常情况下返回的是TRUE 或这FALSE, 特殊值的返回请参阅MSDN. 除了返回值意外, 这两个回调函数似乎没什么不一样, 但实际上并不那么简单. 一个dialog 是一个window, 而它对应的window procedure 是包含在windows 系统中的, 在那个window procedure 中, 会调用到我们的dialog procedure.&lt;br /&gt;dialog 不会收到WM_CREATE 消息, 但是会收到对应的WM_INITDIALOG 消息, 想来是windows 系统在WM_CREATE 消息中重新发的消息吧. 如此一来便可以完成一些dialog 特有的初始化操作. 当我们要用代码销毁一个dialog 的时候, modal 和modeless 这2 中dialog 的方法不同. modal dialog 调用EndDialog(), 而modeless dialog 调用DestroyWindow().&lt;br /&gt;最后, 书上有这样一句话: Unlike messages to modal dialog boxes and message boxes, messages to modeless dialog boxes come through your program's message queue. The message queue must be altered to pass these messages to the dialog box window procedure. 然后说我们要调用IsDialogMessage() 这个API 来传递message. 经过实践, 上面那句话的意思其实是说: modeless dialog 跟window 一样, 默认不支持Tab 键的遍历等键盘消息处理, 但是调用了这个IsDialogMessage() 之后, 所有标记过WS_TABSTOP 的子控件就都支持了. MSDN 上还说, 传入的window 句柄不一定要是dialog, window 也可以. 通过这种方法, 我们通过CreateWindow() 出来的window 也毫不费力的实现Tab 的遍历了. 于是最终, 我们的message loop 的代码大概是这样的(假设hDlgModeless 是一个modeless 的dialog 的handle):&lt;br /&gt;&lt;pre class="brush: cpp"&gt;while(GetMessage(&amp;amp;msg, NULL, 0, 0))&lt;br /&gt;{&lt;br /&gt;if (hDlgModeless == 0 ¦¦ !IsDialogMessage(hDlgModeless, &amp;amp;msg))&lt;br /&gt;{&lt;br /&gt;TranslateMessage(&amp;amp;msg);&lt;br /&gt;DispatchMessage(&amp;amp;msg);&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;如果我们有多个modeless 的dialog, 这种写法岂不是要死人? M$ 的knowledge base 上有篇文章可以参考: &lt;a href="http://support.microsoft.com/kb/71450"&gt;How To Use One IsDialogMessage() Call for Many Modeless Dialogs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;以上. 请继续期待下次GDI 的笔记.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-7613087728619740251?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/7613087728619740251/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=7613087728619740251&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7613087728619740251'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7613087728619740251'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/programming-windows-1.html' title='笔记 - Programming Windows (1)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3714143862138245165</id><published>2009-06-25T04:29:00.004+08:00</published><updated>2011-03-15T16:58:27.686+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='WCF'/><title type='text'>WCF 学习笔记</title><content type='html'>　　WPF(Windows Presentation Foundation), WCF(Windows Communication Foundation), WF(Windows Workflow Foundation) 是.NET 3.0 中新加入的类库. 这里会介绍一下WCF 和WF 的大概应用和架构, 关于WPF, 由于丸子也还没能完全得到那个点, 所以可能就 不介绍了, 还需要在多看看砖头.&lt;br /&gt;&lt;br /&gt;　　进入正题, 今天讲的是WCF. 这个东西是用来创建分布式系统的.&lt;br /&gt;&lt;br /&gt;　　首先介绍一下SOA(Service-Oriented Architecture) 的概念. SOA 实际上是一个基于service 的分布式架构. 每个service 对外提供一定的功能接口. 当我们要做一个大的软件的时候, 只要把这些service 提供的接口组合一下就可以了. 那这些service 之间, 或者我们client 程序之间怎么交互呢? 这里就是SOA 实现的问题了. 比如比较流行的有Web Service, Windows 下比较老的DCOM 和MSMQ. 当然还有WCF. Web Service, WCF 代表的是一种SOA的技术或者说实现, 而它们的通信协议(protocol) 是另外一个概念. 比如Web Service 用的可以是SOAP 或是RESTful 协议. WCF 的好处就是, 把以前的一些技术都整合到了一起, 包括DCOM, MSMQ, .NET remoting, Web Service 等.&lt;br /&gt;　　要建立一个WCF 的应用程序, 基本的组件有三个: a) service assembly, b) service host, c) client. client 端和server 端通信是通过WCF 中的所谓ABC: Address, Binding, Contract. Address 表示的是service 的地址, Binding 表示的是service 的协议, 编码等, Contract 表示的是WCF 对外暴露出的方法.&lt;br /&gt;&lt;br /&gt;　　service assembly 的实现, 主要就是在Contract 这块. 我们用接口(interface) 来定义contract, 然后再用一个具体的类来实现它. 比如:&lt;br /&gt;&lt;pre class="brush: csharp"&gt;&lt;br /&gt;// interface&lt;br /&gt;[ServiceContract]&lt;br /&gt;public interface IService&lt;br /&gt;{&lt;br /&gt;   [OperationContract]&lt;br /&gt;   int Add(int a, int b);&lt;br /&gt;}&lt;br /&gt;// implementation&lt;br /&gt;public class MyService: IService&lt;br /&gt;{&lt;br /&gt;   public MyService()&lt;br /&gt;   {&lt;br /&gt;       /* ... */&lt;br /&gt;   }&lt;br /&gt;   int Add(int a, int b);&lt;br /&gt;   {&lt;br /&gt;       return a + b;&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　然后把以上代码编译成一个dll, 就算完成了.&lt;br /&gt;&lt;br /&gt;　　service host 的稍微复杂一些. 主要用到了System.ServiceModel.ServiceHost 这个WCF 中的类来实现application 级的service host. 大概的代码可能是这样:&lt;br /&gt;&lt;pre class="brush: csharp"&gt;&lt;br /&gt;class MyHost&lt;br /&gt;{&lt;br /&gt;   static void Main(string[] args)&lt;br /&gt;   {&lt;br /&gt;       using (ServiceHost serviceHost = new ServiceHost(typeof(MyService)))&lt;br /&gt;       {&lt;br /&gt;           serviceHost.Open();&lt;br /&gt;           Console.WriteLine("The service is ready.");&lt;br /&gt;           Console.ReadLine();&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　在代码中, 我们在ServiceHost 类的constructor 中传入了MyService 类型作为所要host 的service. 注意, 要调用这个constructor 的话, MyService 类必须有一个不带参数的constructor, 不然运行时会抛错的那. 当然也可以用一个service 的实例来初始化ServiceHost, 但是比较麻烦, 丸子也没研究过.&lt;br /&gt;　　以上的代码显然是缺少Address 和Binding 这两快内容的, 我们要在app.config 的配置文件中指定. 配置文件大概是这样的:&lt;br /&gt;&lt;pre class="brush: xml"&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8" ?&amp;gt;&lt;br /&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;  &amp;lt;system.serviceModel&amp;gt;&lt;br /&gt;      &amp;lt;services&amp;gt;&lt;br /&gt;          &amp;lt;service name="MyServiceLib.MyService"&lt;br /&gt;              behaviorConfiguration="MyServiceMexBehavior"&amp;gt;&lt;br /&gt;              &amp;lt;endpoint address=""&lt;br /&gt;                  binding="basicHttpBinding"&lt;br /&gt;                  contract="MyServiceLib.IService" /&amp;gt;&lt;br /&gt;              &amp;lt;endpoint address=""&lt;br /&gt;                  binding="basicHttpBinding"&lt;br /&gt;                  contract="MyServiceLib.IService2" /&amp;gt;&lt;br /&gt;              &amp;lt;endpoint address="mex"&lt;br /&gt;                  binding="mexHttpBinding"&lt;br /&gt;                  contract="IMetadataExchange" /&amp;gt;&lt;br /&gt;              &amp;lt;host&amp;gt;&lt;br /&gt;                  &amp;lt;baseAddresses&amp;gt;&lt;br /&gt;                      &amp;lt;add baseAddress ="http://localhost:8080/MyService"/&amp;gt;&lt;br /&gt;                  &amp;lt;/baseAddresses&amp;gt;&lt;br /&gt;              &amp;lt;/host&amp;gt;&lt;br /&gt;          &amp;lt;/service&amp;gt;&lt;br /&gt;      &amp;lt;/services&amp;gt;&lt;br /&gt;      &amp;lt;behaviors&amp;gt;&lt;br /&gt;          &amp;lt;serviceBehaviors&amp;gt;&lt;br /&gt;              &amp;lt;behavior name="MyServiceMexBehavior"&amp;gt;&lt;br /&gt;                  &amp;lt;serviceMetadata httpGetEnabled="true" /&amp;gt;&lt;br /&gt;              &amp;lt;/behavior&amp;gt;&lt;br /&gt;          &amp;lt;/serviceBehaviors&amp;gt;&lt;br /&gt;      &amp;lt;/behaviors&amp;gt;&lt;br /&gt;  &amp;lt;/system.serviceModel&amp;gt;&lt;br /&gt;&amp;lt;/configuration&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　好处一串... 先来看&amp;lt;service&amp;gt;这个tag, 它对应的就是contract 的实现类, 用name 属性来指定. 然后是&amp;lt;endpoint&amp;gt;这个tag, 它对应的是单个的contract 的接口. 在运行时, ServiceHost 会进行这样的检查: 根据代码中的MyService 类找到app.config 中对应的&amp;lt;service&amp;gt;的tag, 这个tag 中的name 属性默认就是类名, 但是也可以指定为一个friend name, 不过具体做法未知=v=. 然后分别比对实现类和config 文件中的接口定义是否一致, 如果不一致的话会抛运行时错误. 注意: 我们在所有的&amp;lt;endpoint&amp;gt;中的address 属性都为空, 其实是利用了下面的&amp;lt;baseAddresses&amp;gt;中的baseAddress 属性, 这是一个基地址.&lt;br /&gt;　　另外还有一个MEX(Metadata Exchange) 的概念, 在config 文件中, 对应一个&amp;lt;endpoint&amp;gt;和&amp;lt;behavior&amp;gt;的tag. 简单来说, 这个东西就是用来生产client 端的代理(proxy) 代码的. 它提供了对于metadata 请求的响应. 当运行这个service host 的时候, 我们可以用browser 来访问mex 这个&amp;lt;endpoint&amp;gt;中的address, 会看到关于这个service 的metadata 信息, 以及如何生产client 端代码的提示. 一旦我们生产了client 端的代码, 如果不希望这些metadata 信息再被发现(discover) 的话, 可以删掉这两个tag.&lt;br /&gt;　　注意, &lt;strong&gt;如果是vista或者win7 的话, service host 程序必须以管理员权限运行&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;　　最后就是client 端的写法了. client 端怎样通过WCF 的框架来调用远程的service 呢? 我们需要一个proxy 的类, 这个类通过在service host 得到的metadata 信息, 来封装对于service 的远程调用. vs2008 提供了wizard 来实现这个繁冗的过程, 请自由的在项目节点上右键点击add service reference 菜单项. 在出现的对话框中, 会看到service 的列表, 而每个service 包含多个service contract, 而每个service contract 又包含多个operation contract. 我们要生成的proxy 类的代码是service 级别的, 对于每个service, 所有的代码都生成在一个namespace 中. 一旦生产了代码, 我们的client 端代码将是非常简单的:&lt;br /&gt;&lt;pre class="brush: csharp"&gt;&lt;br /&gt;class MyClient&lt;br /&gt;{&lt;br /&gt;    static void Main(string[] args)&lt;br /&gt;    {&lt;br /&gt;        using (MyServiceClient client = new MyServiceClient())&lt;br /&gt;        {&lt;br /&gt;            Console.Write("{0} + {1} = {2}", 1, 1, client.Add(1,1));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　WCF 还提供了异步调用和自定义数据类型的支持, 这些就请自行查阅MSDN 吧.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3714143862138245165?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3714143862138245165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3714143862138245165&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3714143862138245165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3714143862138245165'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/wcf-1.html' title='WCF 学习笔记'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2207952297987286897</id><published>2009-06-24T04:24:00.005+08:00</published><updated>2011-03-15T16:58:57.050+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>ADO.NET 学习笔记(3)</title><content type='html'>　　今天主要介绍一下LINQ(Language Integrated Query) 在ADO.NET 中的使用, 即LINQ to ADO.NET.&lt;br /&gt;&lt;br /&gt;　　LINQ to ADO.NET 有两个model: LINQ to DataSet 和LINQ to SQL. 我不想讲LINQ 的语法, 主要讲架构.&lt;br /&gt;&lt;br /&gt;　　首先是LINQ to DataSet. 显然, 这套API 就是在DataSet 这套API 上加入了LINQ 的支持. 这个附加的namespace叫做System.Data.DataExtension.dll. 于是我们看到了一个为了LINQ 在.NET 3.5 新加的特性叫做extension method. Extension method 的作用是扩展现有类, 但是不修改源码, 不使用继承或者组合. 只要新加几个函数, 就能让原来的类包含新的方法, 像这些方法本来就被定义了一样. 比如有一个DataTableExtensions 类, 它就在DataTable 类上新加入了AsEnumerable() 方法, 从而把DataTable 类转化成LINQ 兼容的接口类型IEnumerable&amp;lt;T&amp;gt;. 关于extension method 请查阅MSDN.&lt;br /&gt;&lt;br /&gt;   　　然后是LINQ to SQL. 这套API 的目的是要提供数据库到代码的一致的映射关系, 也就是说, 我们不要直接操作int, string 等基本数据类型, 而是操作具体的代码层的映射类. 可以跟java 中的hibernate 比对一下, hibernate 里的映射类叫做POJO(Plain Ordinary Java Objects), 而.NET 中则叫做实体类(entity class). 丸子已经很久没写过java 了, java 的东西几乎都忘了. 翻了些网页发现javaee 持久性框架也使用了entiry class 的概念, 跟hibernate 不同的是, 大量使用了annotation, 从而使hibernate 里出现的mapping 文件没有必要使用了. 具体参照: &lt;a href="http://salto-db.sourceforge.net/salto-db-generator/plugins/ejb3hibernatedao.html"&gt;http://salto-db.sourceforge.net/salto-db-generator/plugins/ejb3hibernatedao.html&lt;/a&gt;. 而.NET 中与annotation 对应的则是attribute.&lt;br /&gt;   　　要使用LINQ to SQL, 就必须要创建实体类. 那我们用什么对象来访问实体类呢? .NET 中有一个叫做DataContext 的类, 对比java 中hibernate 的话, 可以理解为一个Session 对象. 一般的DataContext 的用法大概是这样:&lt;br /&gt;&lt;pre class="brush: csharp"&gt;&lt;br /&gt;DataContext dbCtx = new DataContext(connString);&lt;br /&gt;Table&amp;lt;XXTable&amp;gt; xxTable = dbCtx.GetTable&amp;lt;XXTable&amp;gt;();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;   　　这里的XXTable 类假设是已经定义的实体类. 这样以后就可以对这个xxTable 对象进行操作了. 更好的方法是定义一个strongly typed 的DataContext 类:&lt;br /&gt;&lt;pre class="brush: csharp"&gt;&lt;br /&gt;public class MyDataContext : DataContext&lt;br /&gt;{&lt;br /&gt;   public Table&amp;lt;MyTable1&amp;gt; table1;&lt;br /&gt;   public Table&amp;lt;MyTable2&amp;gt; table2;&lt;br /&gt;   public MyDataContext(string connString) : base(connString) { /* ... */ }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;   　　这又是一个非常神奇的类. 假设MyTable1 和MyTable2 都是已定义的实体类, 所有我们所要做的只是简单的把它们定义成public 的field. 每次当我们调用MyDataContext 的时候, 这些table 的field 会自动被填充. 根据reflector 的trace, 大概是用到了reflection 的机制. 之所以要写一个strongly type 的DataContext, 当然是为了不要繁琐的调用GetTable() 这个方法.&lt;br /&gt;   不过, strongly type 的DataContext 的最主要的作用, 还是从对entity class 的操作转换为对数据库的操作. 再回忆一下, 为什么要有entity class? 因为LINQ 的需要, 需要一个跟数据库一一映射的代码类. 于是, 所有的东西都联系起来了.&lt;br /&gt;   　　vs2008 提供了wizard 来生产这样的DataContext, 菜单位于project--&amp;gt;add new item--&amp;gt;data--&amp;gt;linq to sql classes. 我们有了这个DataContext 之后, 所有的操作应该都是OO 的了, 也会方便很多.&lt;br /&gt;&lt;br /&gt;   　　最后, 从.NET 3.0 开始, assembly 的位置似乎发生了变化. v2.0 的位置在: C:\Windows\Microsoft.NET\Framework, 而v3.0/v3.5 的位置则在: C:\Program Files\Reference Assemblies\Microsoft\Framework.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2207952297987286897?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2207952297987286897/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2207952297987286897&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2207952297987286897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2207952297987286897'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/adonet-3.html' title='ADO.NET 学习笔记(3)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-142428755903306055</id><published>2009-06-23T02:47:00.004+08:00</published><updated>2011-03-15T16:59:14.256+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>ADO.NET 学习笔记(2)</title><content type='html'>　　Disconnected Layer, 在内存中进行把数据库的操作, 然后把这些操作更新回数据库.&lt;br /&gt;&lt;br /&gt; 　　这里有一个data adaptor 的概念. 它使用DataSet 类来进行内存中和数据库中数据的移动和更新. Disconnect Layer 只保持最短时间的数据库连接, 所有的数据库操作都是针对内存中的DataSet 的. 所有操作完成后, 再一次完全更新回实际的数据库. 一个DataSet 类中包含三个collection: DataTableCollection, DataRelationCollection 和PropertyRelation, 分别表示所有的table, 所有的relation, 以及这个dataset 中一些附加的属性.&lt;br /&gt; 　　这里又有个东西叫做data-binding. 所谓的数据绑定, 意思就是说把数据(data)和界面(UI) 联系起来, 当数据发生变化的时候, 界面也会做出相应的改变. 好处是节省了很多手动需要refresh 的代码, 坏处确实这个机制会比较慢. 在windows form 中, 我们可以把一个DataTable 类的实例绑定到一个DataGridView 的DataSource 属性上. DataTable 这个类另外支持一个filter criteria 的功能, 其实就是一个查询条件. 这个功能个人觉得比较弱, 没有java 中hibernate 的HQL 的OO 特性, 也不像hibernate 的Criteria 类完全强类型那么好用.&lt;br /&gt; 　　有一个神奇的类DbCommandBuilder. 这个类可以简化与DataTable 类的CRUD (create/read/update/delete) 操作. 已经提过, 在Disconnected Layer 中, 是通过data adaptor 来进行CRUD 操作的. 拿SqlDataAdaptor 这个类来说, 使用前需要指定它的四个Command 属性: SelectCommand, InsertCommand, DeleteCommand, UpdateCommand. 于是有一个SqlCommandBuilder 类, 它可以根据设定的SelectCommand 来生产其它三个Command 对象. 猜想一下, 应该是根据SelectCommand 可以拿到的DB Scheme 来构造其它Command 的, 而事实就是如此. 缺点是使用DbCommandBuilder 有诸多限制, 请查阅MSDN.&lt;br /&gt;&lt;br /&gt; 　　最后, 要提到一个DAL(Data Access Library) 的概念, 可以跟java 中DAO 联系一下, 其实就是要封装了一些数据库的操作. 在windows form 的DataGridView 的设计界面上, 我们不但可以用wizard 来绑定数据, 同时还生成了所谓的DAL. 生产的代码就是strong-type 的DataSet 和DataTable 类型. 另外, 即使不使用windows form, vs2008 也提供了生产DAL 的wizard, 菜单位于project--&amp;gt;add new iterm--&amp;gt;data--&amp;gt;dataset. 注意, 这里生产的代码还不是OO 的, 我们操作的依然是基本数据类型, 并没有java 中hibernate 的所谓entiry class 相关概念. 关于entiry class, 会在之后的LINQ 中介绍.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-142428755903306055?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/142428755903306055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=142428755903306055&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/142428755903306055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/142428755903306055'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/adonet-2.html' title='ADO.NET 学习笔记(2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-2737248046377219316</id><published>2009-06-22T02:44:00.002+08:00</published><updated>2011-03-15T16:59:30.562+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>ADO.NET 学习笔记(1)</title><content type='html'>　　即日起将开始记录.NET 相关的一些笔记, 将会涉及ADO.NET, WPF, WCF, WF. 今天主要是ADO.NET 的内容.&lt;br /&gt;&lt;br /&gt;　　ADO(Active Data Object) 是M$ 的一个数据访问模型, ADO.NET 自然就是这个东西的.NET 升级版. ADO.NET 可以以两种方式使用: 连接的(connected) 和非连接的(disconnected).&lt;br /&gt;&lt;br /&gt;　　Connected Layer, 可以想象成java 里的jdbc 的数据库访问模型. 我们通过一个Connection 对象连接到数据库, 然后用这个Connection 对象创建一个Statement 对象用来select/insert/delete/update 数据库, 最后调用这个Statement 的executeQuery()/executeUpdate() 方法来完成实际的数据库操作.&lt;br /&gt;  　　这些东西在.NET 里的对应关系大概是这样: Connection--&amp;gt;Connection, Statement--&amp;gt;Command, ResultSet--&amp;gt;DataReader. 这里有一个data provider 的概念, 一个data provider 定义了一系列的数据类型, 用来针对某个特定的数据库类型. 比如针对SQLServer 和Oracle, 分别有(SqlConnection, OracleConnection 类), (SqlCommand, OracleCommand 类) 等. 从类库中来看的话, 一个data provider 实际对应了一个namespace, 比如SQLServer--&amp;gt;System.Data.SqlClient, Oracle--&amp;gt;System.Data.OracleClient. 而在这些namespace 中, 又分别有所谓的provider factory, 比如SqlClientFactory, OracleClientFactory 类, 这些factory 类都继承DbProviderFactory 这个基类.&lt;br /&gt;  　　也许有些晕了, 丸子sensei 告诉你, 这里就是一个&lt;strong&gt;Abstract Factory&lt;/strong&gt; 的设计模式. 把DbProviderFactory 这个类看出抽象基类, coding 的时候把数据库相关的具体实现类用基类来引用. 我们知道一个具体的factory 实际上就是用来创建数据库相关的具体操作类的. 所以通过abstract factory 的这一层抽象, 我们做到了全部用抽象方法的调用. 但是还有一个问题, 那就是当我们把一个具体的DbProviderFactory 赋给基类来使用, 是要手动改代码的, 有没有一中方法可以随便换data provider 而不用改代码呢? 显然, 就是使用一个叫做DbProviderFactories 的类, 这个类有个方法可以接受string 来返回一个DbProviderFactory 的具体实现类.&lt;br /&gt;  　　其实java 用的也是类似的abstract factory 模式, 你一定用 Class.forName("xxx.xxx.xxxDriver").newInstance() 来注册一个driver, 然后再用DriverManager 类的static 方法来返回一个Connection 对象. jdk6.0 中开始包含了jdbc4.0 的新特性, Class.forName() 可以不必调用了.&lt;br /&gt;&lt;br /&gt;  　　关于Disconnected Layer, 请期待下文.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-2737248046377219316?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/2737248046377219316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=2737248046377219316&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2737248046377219316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/2737248046377219316'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/adonet-1.html' title='ADO.NET 学习笔记(1)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1502817605638566305</id><published>2009-06-12T10:41:00.002+08:00</published><updated>2011-03-15T16:32:00.574+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>丸子日记 20090612</title><content type='html'>发信人: gonwan (丸子·请让我飞翔), 信区: gonwan&lt;br /&gt;标  题: 丸子日记 20090612&lt;br /&gt;发信站: 燕曦BBS (2009年06月12日22:51:01 星期五), 站内&lt;br /&gt;&lt;br /&gt;　　最近公司一直在training, 而我就是那个上课时无聊看闲书的那个.&lt;br /&gt;&lt;br /&gt;　　六月中了, 按计划是月底要看完某三本砖头. 但是由于低估了第一本砖头的难度, 且要准备training 的缘故, 导致现在一本也没有看完.&lt;br /&gt;　　事情就是这样, 我们会制定计划, 即使大多数时候计划完全都没用. 但是, 下一次, 我们还是会定计划.&lt;br /&gt;&lt;br /&gt;　　所谓的闲书, 是某本心理学方面的书. 心理学的书好像看的已经是第三本了, 事实证明它非常的有用. 这是一个外国人写的书, 一般外国人写书都会偏理论. 不同的人, 对于同一件事为什么看法会不同呢? 因为性格因素. 那性格又是如何养成的呢? 那是从从小的生长环境. 我们对于环境的反应, 本能的是为了保护自己. 很简单的例子, 小孩子打架被欺负. 一位妈妈对孩子说, 别人打你, 你也打他. 另一位妈妈对孩子说, 妈妈帮你找那孩子去. 可能同样能达到保护自己的结果, 但是对于孩子的影响却不一样, 而这些不一样就对以后的性格取向产生了影响.&lt;br /&gt;　　很多时候, 我们要客观的看到问题, "旁观"而不是"参与", 所谓旁观者清, 不要被性格因素影响.&lt;br /&gt;&lt;br /&gt;　　最近有些想要关版的想法. 几乎变成了帖文版, 好像没什么意义了. 找个个人版挂个b2, b3 似乎也不错.&lt;br /&gt;　　看的越多, 听的越多, 越觉得自己的无知和低俗. 前人的经验告诉我, 事情是可以这样或是那样的, 没必要作茧自缚.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1502817605638566305?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1502817605638566305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1502817605638566305&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1502817605638566305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1502817605638566305'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/20090612.html' title='丸子日记 20090612'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-7543190005839439578</id><published>2009-06-02T22:22:00.007+08:00</published><updated>2011-03-15T17:00:24.648+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='COM'/><category scheme='http://www.blogger.com/atom/ns#' term='Essential COM'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>笔记 - Essential COM (1.2)</title><content type='html'>　　依然是补充内容, 还是跟继承相关, 不过这次还有模板(template).&lt;br /&gt;&lt;br /&gt;　　直接看代码吧:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;template &amp;lt;class T&amp;gt;&lt;br /&gt;class Array {&lt;br /&gt;public:&lt;br /&gt;    virtual int Compare(const Array&amp;lt;T&amp;gt;&amp; rhs) = 0;&lt;br /&gt;    bool operator&amp;lt; (const Array&amp;lt;T&amp;gt;&amp; rhs)&lt;br /&gt;    { return this-&amp;gt;Compare(rhs) &amp;lt; 0; }&lt;br /&gt;    bool operator&amp;gt; (const Array&amp;lt;T&amp;gt;&amp; rhs)&lt;br /&gt;    { return this-&amp;gt;Compare(rhs) &amp;gt; 0; }&lt;br /&gt;    bool operator== (const Array&amp;lt;T&amp;gt;&amp; rhs)&lt;br /&gt;    { return this-&amp;gt;Compare(rhs) == 0; }&lt;br /&gt;private:&lt;br /&gt;    T m_rg[1024];&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　这是一个数组模板类, 提供了数据类型无关的一系列比较操作, 子类需要重载的就是Compare() 这个纯虚函数了. 比如有一个字符串的类:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;class String : public Array&amp;lt;char&amp;gt; {&lt;br /&gt;public:&lt;br /&gt;    int Compare(const Array&amp;lt;char&amp;gt;&amp; rhs)&lt;br /&gt;    { return strcmp(m_rg, rhs.m_rg); }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　这样的写法似乎是理所应当的, 但是考虑一下之前笔记1.1 中关于vptr, vbtl 的内容, 使用虚函数首先会层加4 个byte 的内存开销, 而且later binding 的操作过程相对于其它运算以及函数调用操作是非常慢的. 于是M$ 的童鞋们想出了不用虚函数, 也能实现动态绑定的方法, 还是继续看代码:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;template &amp;lt;class T, class Deriving&amp;gt;&lt;br /&gt;class Array {&lt;br /&gt;public:&lt;br /&gt;    bool operator&amp;lt; (const Array&amp;lt;T, Deriving&amp;gt;&amp; rhs)&lt;br /&gt;    { return static_cast&amp;lt;Deriving* &amp;gt;(this)-&amp;gt;Compare(rhs) &amp;lt; 0; }&lt;br /&gt;    bool operator&amp;gt; (const Array&amp;lt;T, Deriving&amp;gt;&amp; rhs)&lt;br /&gt;    { return static_cast&amp;lt;Deriving* &amp;gt;(this)-&amp;gt;Compare(rhs) &amp;gt; 0; }&lt;br /&gt;    bool operator== (const Array&amp;lt;T, Deriving&amp;gt;&amp; rhs)&lt;br /&gt;    { return static_cast&amp;lt;Deriving* &amp;gt;(this)-&amp;gt;Compare(rhs) == 0; }&lt;br /&gt;private:&lt;br /&gt;    T m_rg[1024];&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　在模板参数中, 我们加入了子类的类型, 所以在父类中, 就可以用static_cast 来转成特定的子类类型来进行操作, 而不是到vptr 那边兜个圈子了. 而接下来只要保证String 类继承Array 类, 就不会有类型不对之类的发满出现了:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;class String : public Array&amp;lt;char, String&amp;gt; {&lt;br /&gt;public:&lt;br /&gt;    int Compare(const Array&amp;lt;char, String&amp;gt;&amp; rhs)&lt;br /&gt;    { return strcmp(m_rg, rhs.m_rg); }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　这样的做法, 既节省了vptr 和vbtl 的内存开销, 又大大提高了performance.&lt;br /&gt;　　可能会有这样的疑问: a) 定义类的时候, 把自己的类型作为模板参数可以么? 答案是可以, template 的标准并没有说不可以. b) 定义Array 类的时候, 并不知道有Compare() 这个函数, 也可以调用? 丸子告诉你, 你一定是java写多了, C++ 就是这样的, 的确有些类型不安全. &lt;br /&gt;&lt;br /&gt;　　以上. 刚才说了这是M$ 的人想出来的, 而这也是ATL(Active Template Library) 的基础.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-7543190005839439578?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/7543190005839439578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=7543190005839439578&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7543190005839439578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/7543190005839439578'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/essential-com-12.html' title='笔记 - Essential COM (1.2)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3283512581953372960</id><published>2009-06-02T21:21:00.007+08:00</published><updated>2011-03-15T17:00:35.033+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='COM'/><category scheme='http://www.blogger.com/atom/ns#' term='Essential COM'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>笔记 - Essential COM (1.1)</title><content type='html'>　　首先解释一下, COM 这个东西真的非常的难入门啊. 1.1 只是为了说明一些补充内容, 不算正式笔记嗯.&lt;br /&gt;　　本文主要说一下C++ 中多重继承的一些问题.&lt;br /&gt;&lt;br /&gt;　　要自己写一个COM 组件, 最最最简单的大概是这样的一个结构: 写2 个interface 继承IUnknown 接口, 然后再写一个实现类实现这两个interface.&lt;br /&gt;　　这里假设的是我们用的是C++ 来实现COM 组件.　因为C++ 中没有语言级别的interface 的支持, 所以SDK 中interface 实际上被typedef 成了struct, 以保证所有申明的接口都默认就是public 的访问权限. 于是这就涉及到了C++ 中多继承的概念. 先不说COM, 假设已经有如下的类定义:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;class ClassA&lt;br /&gt;{&lt;br /&gt;};&lt;br /&gt;class ClassB : /*virtual*/ public ClassA&lt;br /&gt;{&lt;br /&gt;};&lt;br /&gt;class ClassC : /*virtual*/ public ClassA&lt;br /&gt;{&lt;br /&gt;};&lt;br /&gt;class ClassD : public ClassB, public ClassC&lt;br /&gt;{&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　可以把ClassA 想像成IUnknown 接口, ClassB 和ClassC 想像成接口类, ClassD 就是实现类. COM 的标准是不允许使用虚拟基类, 即被注释掉的virtual 关键字, 理由是各厂家的编译器在实现这个feature 的时候, 二进制的格式不统一. 这里牵涉到一个vptr(virtual pointer), vtbl(virtual table) 的概念. 简单来说, C++ 中任何带有虚函数的类都会存在vptr 和vtbl, 它们的作用就是负责动态绑定. vptr 和vtbl 都是编译器生成而程序员是不能手动控制的(有些编译器指令大概可以). vptr 是一个指针指向vtbl, vtbl 是一个类似数组的东西, 它保存了当前类中所有虚函数的实际绑定地址.&lt;br /&gt;　　更详细的内容可以参考: &amp;lt;&amp;lt;Inside the C++ Object Model&amp;gt;&amp;gt; 第4.3 节. 然后有一段代码可以帮助更好的理解vptr 和vtbl: &lt;a href="http://www.go4expert.com/forums/showthread.php?t=8403"&gt;http://www.go4expert.com/forums/showthread.php?t=8403&lt;/a&gt;&lt;br /&gt;　　知道了以上这些之后, 再来看如下代码:&lt;br /&gt;&lt;pre class="brush: cpp"&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    ClassD *pD = new ClassD;&lt;br /&gt;    printf("pD=%p\n", pD);&lt;br /&gt;    ClassB *pB = (ClassB *)pD;&lt;br /&gt;    ClassC *pC = (ClassC *)pD;&lt;br /&gt;    printf("pB=%p\n", pB);&lt;br /&gt;    printf("pC=%p\n", pC);&lt;br /&gt;    ClassA *pA1 = (ClassA *)pB;&lt;br /&gt;    ClassA *pA2 = (ClassA *)pC;&lt;br /&gt;    printf("pA1=%p\n", pA1);&lt;br /&gt;    printf("pA2=%p\n", pA2);&lt;br /&gt;    delete pD;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;　　以下是我机器上的执行结果:&lt;br /&gt;pD=00161A88&lt;br /&gt;pB=00161A88&lt;br /&gt;pC=00161A89&lt;br /&gt;pA1=00161A88&lt;br /&gt;pA2=00161A89&lt;br /&gt;　　惊讶吧? 作为父类实例的pC 指针跟作为子类实例的pD 指针居然不相等. 为什么呢? 就是因为vptr 的影响. 注意: 只有多重继承的时候才会这样. 单继承的时候指针的转换还是相等的, 比如pB 和pD 指针. 而相对的, 因为包含ClassA 的两重数据, pA1 和pA2 也是不相等的.&lt;br /&gt;　　让我们把virtual 关键字加上再试试结果看会怎么样吧?&lt;br /&gt;pD=005D1A88&lt;br /&gt;pB=005D1A88&lt;br /&gt;pC=005D1A8C&lt;br /&gt;pA1=005D1A90&lt;br /&gt;pA2=005D1A90&lt;br /&gt;　　我们看到pB 和pC 之间差了4 个byte, 而之前是1 个byte. 看来虚拟基类果然把C++ 的vptr 结构改了呢. 具体怎么改的我也暂时没能力探明=v=. 说这个只是为了证明: C++ 中的虚拟基类是会破坏COM 的二进制兼容性的.&lt;br /&gt;&lt;br /&gt;　　以上.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3283512581953372960?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3283512581953372960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3283512581953372960&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3283512581953372960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3283512581953372960'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/06/essential-com-11.html' title='笔记 - Essential COM (1.1)'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5004082042538799312</id><published>2009-05-30T10:37:00.001+08:00</published><updated>2011-03-15T16:32:00.575+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>丸子日记 20090530</title><content type='html'>发信人: gonwan (丸子·请让我飞翔), 信区: gonwan&lt;br /&gt;标  题: 丸子日记 20090530&lt;br /&gt;发信站: 燕曦BBS (2009年05月31日00:12:42 星期天), 站内&lt;br /&gt;&lt;br /&gt;　　三天长假, 一天出游, 一天宅家, 一天聚会.&lt;br /&gt;&lt;br /&gt;　　虽然上班时有迟到, 但是聚会一般都会非常守时.&lt;br /&gt;　　一定是太久没有K 歌的缘故, 一首&lt;&lt;许愿池边的希腊少女&gt;&gt;, 一首&lt;&lt;舞娘&gt;&gt;, 到了第三首&lt;&lt;如果没有&gt;&gt; 就觉得气息控制不来.&lt;br /&gt;　　又被认成是小dd 了呢, 这次是07 级的, 暗笑. 衣服上跳跃的黄色, 小小的银丝框眼镜, 小小的书包样的笔记本包. 我在想要不要换成格子衬衫, 黑框眼镜呢?&lt;br /&gt;　　杀人, 三国杀, 我果然对于此类游戏很没有天赋, 不得要领. 经验是一种很可怕的东西, 三国杀也好, 做人也好, 只是后者叫做阅历.&lt;br /&gt;　　平常心很重要.&lt;br /&gt;　　很多事不一定就要做到, 不是么? 即使有那么些事一定要做到.&lt;br /&gt;　　大多数时候, 只是我们把重要的事和紧迫的事搞混了而已吧.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5004082042538799312?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5004082042538799312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5004082042538799312&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5004082042538799312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5004082042538799312'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/08/20090530.html' title='丸子日记 20090530'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-785829999781750619</id><published>2009-05-26T23:44:00.002+08:00</published><updated>2011-03-15T16:32:00.575+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>等我驯服了GFW</title><content type='html'>　　我便忘记原来想写点什么了.. 我艹.&lt;br /&gt;&lt;br /&gt;　　上周和上上周看完一本13xx页的砖头, .NET 相关, WPF, WCF, WF, LINQ 看的真是非常的想死啊. 为什么要看这个? 因为要training, 囧... 为什么要training? 因为闲, 更囧... 我很闲么? 不.. 我有很多事, 囧死了... 唉.. 可怜对于.NET 平台向来没什么好感的我啊...&lt;br /&gt;　　自从重新研读了&amp;lt;&amp;lt;design pattern&amp;gt;&amp;gt;之后, 发现看砖头书快了不少. 一些东西为什么要这么做, 很多情况下都是by design. 为什么.NET 要支持property 这个feature? 因为要支持encapsulation. 为什么很多IO类都实现IDisposable 接口? 因为要能够统一的释放文件句柄. 为什么对于database 的操作全部基于interface? 因为这就是一个abstract factory 的设计模式. 这本书可以说是九阳神功, 练完只有内力没有武功, 而像&amp;lt;&amp;lt;windows internals&amp;gt;&amp;gt;, &amp;lt;&amp;lt;essential com&amp;gt;&amp;gt; 之类的就相当于乾坤大挪移和太极. 这个比喻好雷啊=v=...&lt;br /&gt;&lt;br /&gt;　　唉唉.. 我真的忘记原来要写什么了. 只是五月份以来, 感觉的确轻松了不少.&lt;br /&gt;　　可悲可叹, 我并没有那么看重感情, 那么相信感情了呢.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-785829999781750619?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/785829999781750619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=785829999781750619&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/785829999781750619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/785829999781750619'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/05/gfw_26.html' title='等我驯服了GFW'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-1050151157472464705</id><published>2009-05-25T23:17:00.002+08:00</published><updated>2011-03-15T16:39:05.589+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='GFW'/><title type='text'>GFW 翻墙工具</title><content type='html'>　　那众所周知邪恶的GFW 我就不多介绍了, 直接进主题:&lt;br /&gt;&lt;br /&gt;1) &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/2864"&gt;gladder&lt;/a&gt;&lt;br /&gt;　　这是firefox 的扩展, 利用的是在线代理. 缺点是https 不支持.&lt;br /&gt;&lt;br /&gt;2) &lt;a href="http://www.torproject.org/index.html"&gt;tor&lt;/a&gt;&lt;br /&gt;　　基于tor 协议, 具体是什么我也不清楚. 对于firefox 来说有一个torbutton 的扩展, 很方便. 缺点是非常的慢...&lt;br /&gt;&lt;br /&gt;3) &lt;a href="http://www.your-freedom.net/index.php"&gt;your freedom&lt;/a&gt;&lt;br /&gt;　　基于java 的代理工具, 具体实现好像跟tor 很像, 也不太清楚, 运行一个简单的jar 文件就搞定了. 能https, 速度的话最大64k/s, 个人觉得下片子够了, 呵呵.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-1050151157472464705?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/1050151157472464705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=1050151157472464705&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1050151157472464705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/1050151157472464705'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/05/gfw.html' title='GFW 翻墙工具'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-5995194297617670818</id><published>2009-05-14T19:03:00.007+08:00</published><updated>2011-03-15T17:01:00.916+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Zip Compression Bug in JDK was Fixed</title><content type='html'>　　The long-living zip compression file name encoding bug in JDK was finally fixed. Since the original ZipEntry class will encode/decode the file name in platform's native encoding, one zip file created under one codepage cannot be decoded correctly under another codepage. The workaround is to use the ZipEntry class in the &lt;a href="http://ant.apache.org/"&gt;ant project&lt;/a&gt;. But in current JDK7 early access, the ZipEntry class also added the encoding support as the ant project.&lt;br /&gt;　　This feature was found occasionally when I checked the JDK7 project's changeset:&lt;br /&gt;&lt;a href="http://download.java.net/jdk7/changes/jdk7-b57.html"&gt;http://download.java.net/jdk7/changes/jdk7-b57.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-5995194297617670818?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/5995194297617670818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=5995194297617670818&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5995194297617670818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/5995194297617670818'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/05/zip-compression-bug-in-jdk-was-solved.html' title='Zip Compression Bug in JDK was Fixed'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3219825766233213067</id><published>2009-05-04T13:24:00.002+08:00</published><updated>2011-03-15T16:32:00.576+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>既成事实</title><content type='html'>　　如此, 便不必多说.&lt;br /&gt;　　戒指从右手中指移到左手食指.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-3219825766233213067?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/3219825766233213067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=3219825766233213067&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3219825766233213067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/3219825766233213067'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/05/blog-post.html' title='既成事实'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-6852701139142175769</id><published>2009-04-29T22:18:00.003+08:00</published><updated>2011-03-15T16:32:00.576+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>不安种种</title><content type='html'>　　// 首先抱怨一下, google 的blog 真的没有ycul 的好用 =v=&lt;br /&gt;&lt;br /&gt;  　　最近看了很多闲杂读物, 正经书几乎一页都没看. 呵, 心情因素, 希望五一休假能通通消除干净.&lt;br /&gt;&lt;br /&gt;　　我说我要努力搞好跟家人关系, 这件事还真无语.&lt;br /&gt;　　首先, 几乎每周回家都会陪老妈逛街. 于是, 会发生诸如此类的对话:&lt;br /&gt;-- 我帮你买个外套什么的吧?&lt;br /&gt;-- 不要.. 我自己会买.&lt;br /&gt;-- 你自己又不买.&lt;br /&gt;-- 么钱, 有钱还不如买吃的, 我又不要出去见人.&lt;br /&gt;-- 你好去找个女朋友来, 妈贴你钱.&lt;br /&gt;-- (...) 这件事情不要您操心额...&lt;br /&gt;　　之后, 吃饭了:&lt;br /&gt;-- 妈这个礼拜看了一套房子, 还不错.&lt;br /&gt;-- 在哪里的? 多少平?&lt;br /&gt;-- 就在xxxxx, 大概快60个平方, 侬看哪能?&lt;br /&gt;-- (疑惑...)啥哪能?&lt;br /&gt;-- 侬觉得可以么就买了呀.&lt;br /&gt;-- 60个平方额2室户哪能登啊...&lt;br /&gt;-- 侬以后又伐要跟阿拉登了一道, 个么买小一点, 省点钱给你呀.&lt;br /&gt;-- 吾伐要你们省钱额.. 弄跟老爸住舒服点就好了呀.. 不用管我.&lt;br /&gt;-- 伐来三..原来的房子拆迁本来就有侬一份额呀.&lt;br /&gt;-- (...) 个么用得着噶急伐啦? 刚拆迁么多少辰光就买房子.&lt;br /&gt;-- 个么是额呀.. 侬下次要是要带女朋友回来, 阿拉租额房子, 个多少戆啦.&lt;br /&gt;-- (...) 这件事情真的不需要您操心额...&lt;br /&gt;-- 伐来三额.. 个哪能来三呢... xxxxxxx&lt;br /&gt;  　　我基本已经很无语了, 每周如此, 上午下午还个来一遍, 呵. 到底要管我到什么时候呢? 于是我觉得自己租房的时间可能还要延长, 果然我需要的就是即成事实, 让所有人闭嘴.&lt;br /&gt;&lt;br /&gt;　　然后, 再来说说女人吧... 我觉得我找不出任何一个让人不喜欢的地方, perfect. 以下内容可能措辞不明, 能表示我的意思就是了.&lt;br /&gt;  　　我还记得当初说喜欢她什么, 现在看来那些都只是表面, 其实"成熟"这一个词就能概况了. 嗯, 至少比起当时的我. 而"成熟"的另外一面就是... 很多事情我不知道, 当然我也应该是不知道的吧. 如果我真的不知道那些, 大概就没有现在的不安了吧. 但是我现在知道么? 知道. 所以我不安. (某痞子gx你, 我篡改了你的话 ! )&lt;br /&gt;　　毕业的时候, 我想, 都算了吧, 先工作吧, 既然在学校的时候没女人, 工作了就会更麻烦吧. 当时真的一点想法也没有呢, 但是最后一句还真是有预见性. 为什么这么说呢? 各有各的道理吧. 当老妈一再的催促我把这事提上议事日程的时候, 我也不得不再来认真的思考一番, 我到底是出于怎么样的想法啊. 答案是没有想法. 或者原来有的, 现在也没有了吧.&lt;br /&gt;  　　我们都在变, 因为周围的人都在变.&lt;br /&gt;　　我试着想起种种的好处来填充自己的不安, 但是发现无法, 后来更发现这两个东西根本没有可比性. 唉...某人每次电话都要讲半天, 而我每个周末也赶场子般的来回也不知所谓.&lt;br /&gt;  　　我是不是要.....&lt;br /&gt;&lt;br /&gt;  　　在然后, 是工作.&lt;br /&gt;　　最近工作非常的无聊, 因为taipei 那边的sx 严重不遵守schedule, 导致老子我几乎没事干. 干的都是一些无关痛痒的活, 然后又没心情看书, 真无语. 严重的精神萎靡中...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;　　最后说说最近看得两部觉得不错的电影吧:&lt;br /&gt;&lt;br /&gt;　　第一部叫做&amp;lt;&amp;lt;西西里的美丽传说&amp;gt;&amp;gt;. 刚看完的时候, 觉得真神奇啊, 完全不知道导演要告诉我什么. 有可能看太投入了, 来不及细想. 之后, 把整个故事串起来想了一遍, 理解了个大概. 到douban 上喵了一眼评论, 觉得理解的还不错. 可以看看这篇评论: &lt;a href="http://blog.sina.com.cn/s/blog_484291c1010002ah.html"&gt;http://blog.sina.com.cn/s/blog_484291c1010002ah.html&lt;/a&gt;. 解答了我为什么女主不自寻短剑, 最后那句淡定的"早上好"是怎么说出口的, 如此看来, 导演真的非常的高明啊...&lt;br /&gt;  　　但是, 我想说的不是这些. 试想, 如果女主的丈夫一开始并没有因为战争而在前线挂掉, 又会怎么样. 那我们的女主就开心啦, 因为能有足够的底气来显示高傲的一面了, 呵呵. 所以, 怕被人妒忌的话, 就一定要足够的牛b.&lt;br /&gt;&lt;br /&gt;  　　第二部叫做&amp;lt;&amp;lt;肖申克的救赎&amp;gt;&amp;gt;. 救赎..一个非常高级的词那. 我依然不评论这个电影的精妙设计之处.&lt;br /&gt;  　　想一下, 我们的大银行家男主, 一开始受"三姐妹"的虐待, 但是为什么后来在其它犯人中间却人气颇高呢? 学识和希望. 学识可以帮助别人, 而希望可以救赎自由. 所以, 请自由的回忆裴多菲的诗句. 而我要说的依然是, 人牛b, 就不会有人妒忌.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/453740415575159373-6852701139142175769?l=gonwan1985.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gonwan1985.blogspot.com/feeds/6852701139142175769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=453740415575159373&amp;postID=6852701139142175769&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6852701139142175769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/453740415575159373/posts/default/6852701139142175769'/><link rel='alternate' type='text/html' href='http://gonwan1985.blogspot.com/2009/04/blog-post_29.html' title='不安种种'/><author><name>gonwan</name><uri>http://www.blogger.com/profile/16471256682350176184</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/-UnIfDF42hQg/TiWf6WWgL1I/AAAAAAAADRY/ZJHGzrlTte0/s220/banner_b.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-453740415575159373.post-3396894898196624395</id><published>2009-04-23T19:27:00.009+08:00</published><updated>2011-03-15T16:32:00.577+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Miscellaneous'/><title type='text'>2 Interesting Quiz</title><content type='html'>&lt;span style="font-weight: bold;"&gt;1. Rate your life&lt;/span&gt;&lt;br /&gt;&lt;a href="http://www.monkeyquiz.com/life/rate_my_life.html"&gt;http://www.monkeyquiz.com/life/rate_my_life.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;My Result:&lt;br /&gt;&lt;table style="border: 1px solid rgb(51, 51, 51); margin: 10px;" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td colspan="2" style="border: medium none ; margin: 0px; padding: 5px; background: rgb(255, 221, 187) none repeat scroll 0% 0%; font-family: sans-serif; font-style: normal; font-variant: normal; font-weight: bold; font-size: 16px; line-height: normal; font-size-adjust: none; font-stretch: normal; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0); text-align: center;"&gt;This Is My Life, Rated&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border-style: solid solid solid none; border-color: rgb(51, 51, 51) rgb(51, 51, 51) rgb(51, 51, 51) -moz-use-text-color; border-width: 1px 1px 1px medium; padding: 5px; background: rgb(255, 255, 204) none repeat scroll 0% 0%; width: 85px; font-family: sans-serif; font-style: normal; font-variant: normal; font-weight: bold; font-size: 18px; line-height: normal; font-size-adjust: none; font-stretch: normal; text-align: left; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0);"&gt;Life:&lt;br /&gt;&lt;/td&gt;&lt;td style="border-style: solid none; border-color: rgb(51, 51, 51) -moz-use-text-color; border-width: 1px medium; padding: 5px 5px 5px 0px; background: rgb(255, 255, 255) none repeat scroll 0% 0%; width: 240px; font-family: sans-serif; font-style: normal; font-variant: normal; font-weight: bold; font-size: 18px; line-height: normal; font-size-adjust: none; font-stretch: normal; text-align: left; vertical-align: middle; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; color: rgb(0, 0, 0);"&gt;&lt;img src="http://www.monkeyquiz.com/img/greblubar.gif" style="border-style: solid solid solid none; border-color: rgb(0, 0, 0) rgb(0, 0, 0) rgb(0, 0, 0) -moz-use-text-color; border-width: 1px 1px 1px medium; margin: 0px; padding: 0px; vertical-align: middle;" width="140" height="12" /&gt; 7&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="border-style: none solid none none; border-color: -moz-use-text-color rgb(51, 51, 51) -moz-use-text-color -moz-use-text-color; border-width: medium 1px medium medium; padding: 5px; background: rgb(255, 255, 204) none repeat scroll 0% 0%; widt
