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

<channel>
	<title>Phanix's Blog &#187; 程式</title>
	<atom:link href="http://blog.phanix.idv.tw/archives/category/%e5%ad%b8%e7%bf%92%e5%b7%a5%e4%bd%9c/%e7%a8%8b%e5%bc%8f/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.phanix.idv.tw</link>
	<description></description>
	<lastBuildDate>Tue, 07 Feb 2012 01:03:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>[C#][Maya][Python] Maya commandPort for external communication / 利用 commandPort 命令讓外部程式與 Maya 溝通</title>
		<link>http://blog.phanix.idv.tw/archives/2011/12/28/1009/</link>
		<comments>http://blog.phanix.idv.tw/archives/2011/12/28/1009/#comments</comments>
		<pubDate>Wed, 28 Dec 2011 10:15:31 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[Maya]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=1009</guid>
		<description><![CDATA[利用 tcp client connection 或 socket connection 來跟 Maya 溝通 先給 python 程式&#8230; import socket host = YOUR_HOST_ADDRESS # &#8216;localhost&#8217; or &#8217;127.0.0.1&#8242; for local machine, IP_ADDRESS for remote machine port = YOUR_PORT_NUMBER_OF_MAYA maya = socket.socket(socket.AF_INET, socket.SOCK_STREAM) maya.connect( (host, port) ) message = &#8216;sphere()&#8217; maya.send(message) maya.close() C# 用 socket connection Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, [...]]]></description>
			<content:encoded><![CDATA[<p>利用 tcp client connection 或 socket connection 來跟 Maya 溝通<br />
<span id="more-1009"></span></p>
<p>先給 python 程式&#8230;</p>
<blockquote><p>
import socket</p>
<p>host = YOUR_HOST_ADDRESS # &#8216;localhost&#8217; or &#8217;127.0.0.1&#8242; for local machine, IP_ADDRESS for remote machine<br />
port = YOUR_PORT_NUMBER_OF_MAYA</p>
<p>maya = socket.socket(socket.AF_INET, socket.SOCK_STREAM)<br />
maya.connect( (host, port) )</p>
<p>message = &#8216;sphere()&#8217;<br />
maya.send(message)<br />
maya.close()
</p></blockquote>
<p>C# 用 socket connection</p>
<blockquote><p>
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);<br />
s.Connect(YOUR_HOST_ADDRESS, YOUR_PORT_NUMBER_OF_MAYA);</p>
<p>string strCmd = &#8220;sphere()&#8221;;<br />
byte[] buf = System.Text.Encoding.Default.GetBytes(strCmd);</p>
<p>NetworkStream ns = new NetworkStream(s);</p>
<p>ns.Write(buf, 0, buf.Length);<br />
ns.Flush();<br />
ns.Close();</p>
<p>s.Close();
</p></blockquote>
<p>C# 用 Tcp client connection 的話也差不多</p>
<blockquote><p>
TcpClient tc = new TcpClient();<br />
tc.Connect(YOUR_HOST_ADDRESS, YOUR_PORT_NUMBER_OF_MAYA);</p>
<p>string strCmd = &#8220;sphere()&#8221;;<br />
byte[] buf = System.Text.Encoding.Default.GetBytes(strCmd);</p>
<p>NetworkStream ns = tc.GetStream();</p>
<p>ns.Write(buf, 0, buf.Length);<br />
ns.Flush();<br />
ns.Close();</p>
<p>tc.Close();
</p></blockquote>
<p>比較需要注意的大概是 commandPort 命令的用法。</p>
<p>如果是使用</p>
<blockquote><p>
commandPort -echoOutput -n &#8220;:6000&#8243;;
</p></blockquote>
<p>則會會開 port 6000 並 bind 在 127.0.0.1 上，這時候如果是要從 remote 機器上來控制就會 connection refused。</p>
<p>如果是使用</p>
<blockquote><p>
commandPort -echoOutput -n &#8220;YOUR_IP_ADDRESS:6000&#8243;;
</p></blockquote>
<p>則會會開 port 6000 並 bind 在 YOUR_IP_ADDRESS 上，這時候如果從本機用 localhost 來控制會 connection refused，但是用 YOUR_IP_ADDRESS 則不會有問題。</p>
<p>最簡單的解決方式是</p>
<blockquote><p>
commandPort -echoOutput -n &#8220;0.0.0.0:6000&#8243;;
</p></blockquote>
<p>這樣不論是本機或者 remote 機器來控制 Maya 做事情都可以很順利。</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-7434619175264093";
google_ad_width = 468;
google_ad_height = 60;
google_ad_format = "468x60_as";
google_ad_type = "text_image";
google_ad_channel = "";
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p> ]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2011/12/28/1009/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[C#] XMLWriter Encoding Issue / XMLWriter 控制文字編碼</title>
		<link>http://blog.phanix.idv.tw/archives/2011/12/26/1008/</link>
		<comments>http://blog.phanix.idv.tw/archives/2011/12/26/1008/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 07:12:51 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=1008</guid>
		<description><![CDATA[一般狀況下，如果不是很在意使用 XMLWriter 後輸出的文字編碼是哪一種的話，可以很簡單地用下面的方式完成 StringBuilder sb = new StringBuilder(); XmlWriter writer = XmlWriter.Create(sb); writer.WriteStartDocument(); //補上 xml 內容, 用 writer.WriteStartElement() 等完成 writer.WriteEndDocument(); writer.Flush(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(sb.ToString()); 但是可以發現到這樣子所輸出的 XML 文件是變成 UTF-16 encoding。雖然有 XmlWriterSettings 這東西可以去設定 XMLWriter 的編碼，不過看起來好像是有些問題，輸出的 XML 結果依舊是 UTF-16。 解決的方法是用 MemoryStream 與 XMLTextWriter。 MemoryStream stream = new MemoryStream(); XmlWriter writer = new XmlTextWriter(stream, Encoding.UTF8); writer.WriteStartDocument(); [...]]]></description>
			<content:encoded><![CDATA[<p>一般狀況下，如果不是很在意使用 XMLWriter 後輸出的文字編碼是哪一種的話，可以很簡單地用下面的方式完成</p>
<blockquote><p>
StringBuilder sb = new StringBuilder();<br />
XmlWriter writer = XmlWriter.Create(sb);</p>
<p>writer.WriteStartDocument();<br />
//補上 xml 內容, 用 writer.WriteStartElement() 等完成<br />
writer.WriteEndDocument();</p>
<p>writer.Flush();</p>
<p>XmlDocument xmlDocument = new XmlDocument();<br />
xmlDocument.LoadXml(sb.ToString());
</p></blockquote>
<p>但是可以發現到這樣子所輸出的 XML 文件是變成 UTF-16 encoding。雖然有 XmlWriterSettings 這東西可以去設定 XMLWriter 的編碼，不過看起來好像是有些問題，輸出的 XML 結果依舊是 UTF-16。</p>
<p>解決的方法是用 MemoryStream 與 XMLTextWriter。</p>
<blockquote><p>
<span style="color:red;">MemoryStream stream = new MemoryStream();<br />
XmlWriter writer = new XmlTextWriter(stream, Encoding.UTF8);</span></p>
<p>writer.WriteStartDocument();<br />
//補上 xml 內容, 用 writer.WriteStartElement() 等完成<br />
writer.WriteEndDocument();</p>
<p>writer.Flush();</p>
<p><span style="color:red;">StreamReader reader = new StreamReader(stream, Encoding.UTF8, true);<br />
stream.Seek(0, SeekOrigin.Begin);<br />
string result = reader.ReadToEnd();</span></p>
<p>XmlDocument xmlDocument = new XmlDocument();<br />
xmlDocument.LoadXml(result);
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2011/12/26/1008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[C#] Unix Timestamp</title>
		<link>http://blog.phanix.idv.tw/archives/2011/07/26/969/</link>
		<comments>http://blog.phanix.idv.tw/archives/2011/07/26/969/#comments</comments>
		<pubDate>Tue, 26 Jul 2011 09:48:35 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=969</guid>
		<description><![CDATA[因為 Facebook 上頭記錄時間是用 Unix Timestamp，所以來看一下怎麼做。 Unix Timestamp 的定義為目前 UTC 時間減去 Unix epoch 起始時間(1970/1/1 0:0:0 UTC)所得到的秒數。(Ref: Unix time) private double UnixTimestamp(DateTime _datetime) { //Unix Epoch: 1970/1/1 0:0:0 TimeSpan span = (_datetime - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime()); return (double)span.TotalSeconds; }]]></description>
			<content:encoded><![CDATA[<p>因為 Facebook 上頭記錄時間是用 Unix Timestamp，所以來看一下怎麼做。</p>
<p><span id="more-969"></span></p>
<p>Unix Timestamp 的定義為目前 UTC 時間減去 Unix epoch 起始時間(1970/1/1 0:0:0 UTC)所得到的秒數。(Ref: <a href="http://en.wikipedia.org/wiki/Unix_time" target="_blank">Unix time</a>)</p>
<pre>private double UnixTimestamp(DateTime _datetime)
{
    //Unix Epoch: 1970/1/1 0:0:0
    TimeSpan span = (_datetime - new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime());

    return (double)span.TotalSeconds;
} </pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2011/07/26/969/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# 處理 facebook JSON Serialized Data</title>
		<link>http://blog.phanix.idv.tw/archives/2011/07/19/962/</link>
		<comments>http://blog.phanix.idv.tw/archives/2011/07/19/962/#comments</comments>
		<pubDate>Tue, 19 Jul 2011 02:30:21 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[網路應用]]></category>
		<category><![CDATA[電腦網路]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[Facebook]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=962</guid>
		<description><![CDATA[當透過 access token 去 facebook 抓取資料時，回傳的資料將以 JSON 的方式編碼，在 C# 裡頭可以用 JavaScriptSerializer 來處理，下面是個很懶惰的處理方式，不需要另外先去設計與宣告一個符合 facebook JSON 格式的 class object 來儲存資料，反正需要的時候再來針對 Key 另外處理即可。 using System.Web.Script.Serialization; using System.Collections; using System.IO; private void ProcessFBJSON() { JavaScriptSerializer jss = new JavaScriptSerializer(); string json; StreamReader sr = new StreamReader(@"C:\file.txt", Encoding.Default); json = sr.ReadToEnd(); sr.Close(); Dictionary dicSer = jss.Deserialize(json); traceDic(dicSer); } private void [...]]]></description>
			<content:encoded><![CDATA[<p>當透過 access token 去 facebook 抓取資料時，回傳的資料將以 JSON 的方式編碼，在 C# 裡頭可以用 JavaScriptSerializer 來處理，下面是個很懶惰的處理方式，不需要另外先去設計與宣告一個符合 facebook JSON 格式的 class object 來儲存資料，反正需要的時候再來針對 Key 另外處理即可。</p>
<p><span id="more-962"></span></p>
<pre>using System.Web.Script.Serialization;
using System.Collections;
using System.IO;

private void ProcessFBJSON()
{
    JavaScriptSerializer jss = new JavaScriptSerializer();

    string json;

    StreamReader sr = new StreamReader(@"C:\file.txt", Encoding.Default);
    json = sr.ReadToEnd();
    sr.Close();

    Dictionary<string, object> dicSer = jss.Deserialize<Dictionary<string, object>>(json);

    traceDic(dicSer);
}

private void traceDic(Dictionary<string, object> dic)
{
    foreach (KeyValuePair<string, object> p in dic)
    {
        if (p.Value is String)
        {
            textBox1.Text = textBox1.Text + p.Key + ": " + p.Value + "\r\n";
        }
        else if (p.Value is ArrayList)
        {
            textBox1.Text = textBox1.Text + p.Key + ": {\r\n";
            traceArrayList((ArrayList)(p.Value));
            textBox1.Text = textBox1.Text + "}\r\n";
        }
        else if (p.Value is Dictionary<string, object>)
        {
            textBox1.Text = textBox1.Text + p.Key + ": [{\r\n";
            traceDic((Dictionary<string, object>)(p.Value));
            textBox1.Text = textBox1.Text + "}]\r\n";
        }
        else if (p.Value is int || p.Value is float || p.Value is double)
        {
            textBox1.Text = textBox1.Text + p.Key + ": " + p.Value.ToString() + "\r\n";
        }
        else
        {
            MessageBox.Show("dictionary: " + p.Value.GetType().ToString());
        }
    }
}

private void traceArrayList(ArrayList al)
{
    for (int i = 0; i < al.Count; i++)
    {
        if (al[i] is String)
        {
            textBox1.Text = textBox1.Text + "   " + al[i].ToString() + "\r\n";
        }
        else if (al[i] is Dictionary<string, object>)
        {
            traceDic((Dictionary<string, object>)(al[i]));
        }
        else
        {
            MessageBox.Show("arrlist: " + al[i].GetType().ToString());
        }
    }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2011/07/19/962/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>.NET 取得 windows 帳號資訊</title>
		<link>http://blog.phanix.idv.tw/archives/2011/06/20/938/</link>
		<comments>http://blog.phanix.idv.tw/archives/2011/06/20/938/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 10:43:25 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[Account]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=938</guid>
		<description><![CDATA[取得登入帳號 Environment.UserName 取得帳號等有儲存在本機上的資訊 using System.Security.Principal; using System.Threading; //----- AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); WindowsPrincipal myPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal; WindowsIdentity myIdentity = (WindowsIdentity)myPrincipal.Identity; Console.WriteLine("IdentityType: " + myIdentity.ToString()); Console.WriteLine("Name: {0}", myIdentity.Name); Console.WriteLine("Member of Users? {0}", myPrincipal.IsInRole(WindowsBuiltInRole.User)); Console.WriteLine("Member of Administrators? {0}", myPrincipal.IsInRole(WindowsBuiltInRole.Administrator)); Console.WriteLine("Authenticated: {0}", myIdentity.IsAuthenticated); Console.WriteLine("Anonymous: {0}", myIdentity.IsAnonymous); 取得帳號等有儲存在本機上的資訊 &#8211; II 使用 Win32 API using System.Runtime.InteropServices; //----- [DllImport("Advapi32.dll", EntryPoint="GetUserName", ExactSpelling=false, SetLastError=true)] static extern [...]]]></description>
			<content:encoded><![CDATA[<h2>取得登入帳號</h2>
<p>Environment.UserName</p>
<p><br/><br/><br/></p>
<h2>取得帳號等有儲存在本機上的資訊</h2>
<pre>
using System.Security.Principal;
using System.Threading;

//-----

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);

WindowsPrincipal myPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;

WindowsIdentity myIdentity = (WindowsIdentity)myPrincipal.Identity;

Console.WriteLine("IdentityType: " + myIdentity.ToString());
Console.WriteLine("Name: {0}", myIdentity.Name);
Console.WriteLine("Member of Users? {0}", myPrincipal.IsInRole(WindowsBuiltInRole.User));
Console.WriteLine("Member of Administrators? {0}", myPrincipal.IsInRole(WindowsBuiltInRole.Administrator));
Console.WriteLine("Authenticated: {0}", myIdentity.IsAuthenticated);
Console.WriteLine("Anonymous: {0}", myIdentity.IsAnonymous);</pre>
<p><br/><br/><br/></p>
<h2>取得帳號等有儲存在本機上的資訊 &#8211; II</h2>
<p>使用 Win32 API</p>
<pre>
using System.Runtime.InteropServices;

//-----
[DllImport("Advapi32.dll", EntryPoint="GetUserName",  ExactSpelling=false, SetLastError=true)]
static extern bool GetUserName([MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
						[MarshalAs(UnmanagedType.LPArray)] Int32[] nSize );

//-----
byte[] str = new byte[256];
Int32[] len = new Int32[1];
len[0] = 256;
GetUserName(str, len);
MessageBox.Show(System.Text.Encoding.ASCII.GetString(str));

string a = System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString();

MessageBox.Show(a.ToString());</pre>
<p><br/><br/><br/></p>
<h2>LDAP</h2>
<p>這是可以取得最詳細資訊的方法</p>
<pre>using System.DirectoryServices;

//-----

string principal = Environment.UserName;
string filter = string.Format("(&#038;(ObjectClass={0})(sAMAccountName={1}))", "person", principal);
string[] properties = new string[] { "fullname" };

//用匿名登入，理論上LDAP都會允許，但只有 read 權限
DirectoryEntry adRoot = new DirectoryEntry("LDAP://yourdomain.com", null, null, AuthenticationTypes.Secure);
DirectorySearcher searcher = new DirectorySearcher(adRoot);
searcher.SearchScope = SearchScope.Subtree;
searcher.ReferralChasing = ReferralChasingOption.All;
searcher.PropertiesToLoad.AddRange(properties);
searcher.Filter = filter;
SearchResult result = searcher.FindOne();
DirectoryEntry directoryEntry = result.GetDirectoryEntry();

string displayName = directoryEntry.Properties["displayName"][0].ToString();
string firstName = directoryEntry.Properties["givenName"][0].ToString();
string lastName = directoryEntry.Properties["sn"][0].ToString();
string email = directoryEntry.Properties["mail"][0].ToString();
string department = directoryEntry.Properties["department"][0].ToString();
string description = directoryEntry.Properties["description"][0].ToString();</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2011/06/20/938/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# window form drawing over other controls / 在 window form 中繪製圖形並疊在控制項上</title>
		<link>http://blog.phanix.idv.tw/archives/2011/02/23/901/</link>
		<comments>http://blog.phanix.idv.tw/archives/2011/02/23/901/#comments</comments>
		<pubDate>Wed, 23 Feb 2011 07:14:21 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[panel]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[transparent]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=901</guid>
		<description><![CDATA[本文以中英夾雜並陳 This article is interleaved with Chinese and English. 本來還想在網路上看能不能找到答案的, 結果只有找到一些可能的提示&#8230; 不過最後還是摸索出來了啦 At the beginning, I hope to scrounge the solution from Internet, but after hours of searching, I only find some possible hints. Anyway, here&#8217;s the solution. 之所以會想要弄這樣的功能，是因為要做出類似在檔案總管中用拖曳選取時有半透明選取區域的效果。但是如果在 window form 中匯製矩形時，會發現這個矩形區域會被其他的控制項壓在下面，使得這個半透明的效果變得很奇怪(如下圖). This issue is caused by I wanna make a semi-transparent selection area in [...]]]></description>
			<content:encoded><![CDATA[<p>本文以中英夾雜並陳</p>
<p>This article is interleaved with Chinese and English.</p>
<p>本來還想在網路上看能不能找到答案的, 結果只有找到一些可能的提示&#8230; 不過最後還是摸索出來了啦 <img src='http://blog.phanix.idv.tw/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p>At the beginning, I hope to scrounge the solution from Internet, but after hours of searching, I only find some possible hints. Anyway, here&#8217;s the solution.</p>
<p><span id="more-901"></span></p>
<p>之所以會想要弄這樣的功能，是因為要做出類似在檔案總管中用拖曳選取時有半透明選取區域的效果。但是如果在 window form 中匯製矩形時，會發現這個矩形區域會被其他的控制項壓在下面，使得這個半透明的效果變得很奇怪(如下圖).</p>
<p>This issue is caused by I wanna make a semi-transparent selection area in a window form, just what we usually use in windows file manager. However, if we just draw a rectangle in a window form, this rectangle will be &#8220;overlayed&#8221; by other controls, just like the figure below. Yep, quite weird.</p>
<p><a href="http://www.flickr.com/photos/phanix/5469721099/" title="underlay by Phanix, on Flickr"><img src="http://farm6.static.flickr.com/5176/5469721099_44301821ef_z.jpg" width="562" height="640" alt="underlay" /></a></p>
<p>而我想要的效果是如下圖這樣的, 半透明的選取區域壓在控制項上方.</p>
<p>The figure below is what I really want is a semi-transparent selection region overlays other controls.<br />
<a href="http://www.flickr.com/photos/phanix/5470314074/" title="Overlay by Phanix, on Flickr"><img src="http://farm6.static.flickr.com/5099/5470314074_b2a3f14b4c_z.jpg" width="640" height="577" alt="Overlay" /></a></p>
<p>最開始的時候我的想法是做一個透明的 Panel, 同時給定顏色，然後隨著滑鼠拖曳動態地去調整大小。結果我在網路上找到了製作透明 Panel 的方法(程式碼如下)，但，很遺憾地，對這個透明 Panel 指定顏色還不能達到我想要的效果。</p>
<p>My first trial is creating a transparent Panel and assign some color onto in, and adjust the size as mouse dragging and moving. I scrounged a transparent panel solution from Internet (source code as below), but, unfortunately, assigning color onto it still does not meet what I want.</p>
<blockquote><pre>public class TransparentPanel : System.Windows.Forms.Panel
{
    public TransparentPanel()
    {
    }

    protected override System.Windows.Forms.CreateParams CreateParams
    {
        get
        {
            System.Windows.Forms.CreateParams createParams = base.CreateParams;
            createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT

            return createParams;
        }
    }

    protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
    {
        // Do not paint background.
    }
}</pre>
</blockquote>
<p>那, 在這個透明的 panel 上頭畫一個半透明的矩形呢? 似乎有點可行, 但是在滑鼠拖曳移動時會變得很糟糕, 留下許多殘像.</p>
<p>Well, how about drawing a semi-transparent rectangle on the transparent panel? Sounds reasonable, but there are lots of afterimages while mouse dragging and moving.</p>
<blockquote>
<pre>//draw a semi-transparent rectangle by adjusting the alpha value of Color.FromArgb function.
Rectangle rec = new Rectangle(topLeftRec, howBig);
Graphics.FillRectangle(new SolidBrush(Color.FromArgb(150, 255, 255, 0)), rec);</pre>
</blockquote>
<p>後來看到一些提示之後找到了解法，必須透過控制項的 Paint event 來把這個矩形匯製出來。雖然還不是很清楚為什麼要這樣做，但感覺起來是把這個矩形的匯製的動作跟著控制項匯製的動作綁在一起。藉由改變 transparent panel 的大小與位置來觸發 Paint event.</p>
<p>Finally, with some hints on Internet, I find the solution &#8212; painting the rectangle as a control&#8217;s paint event is triggered. Although I still do not fully understand the reason why I have to follow this process, I think it might require combining drawing rectangle with the control&#8217;s paint process. By changing the size and location of the transparent panel, the Paint event can be triggered.</p>
<blockquote><pre>private void pTransparent_Paint(object sender, PaintEventArgs e)
{
    base.OnPaint(e);
    Graphics dc = e.Graphics;

    Pen blackPen = new Pen(Color.Black, 1);
    Point topLeftRec = new Point(e.ClipRectangle.X, e.ClipRectangle.Y);
    Size howBig = new Size(e.ClipRectangle.Width, e.ClipRectangle.Height);
    Rectangle rec = new Rectangle(topLeftRec, howBig);

    Console.WriteLine(topLeftRec.ToString());

    dc.DrawRectangle(blackPen, rec);
    dc.FillRectangle(new SolidBrush(Color.FromArgb(150, 255, 255, 0)), rec);
    blackPen.Dispose();
}

private Rectangle drawrect;
private bool md = false;
private Point startpoint, drawtopleft;
private Size drawsize;

private void flowLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
{
    if (md == true)  //md is a boolean variable representing in mouse dragging mode or not.
    {
        drawtopleft.X = Math.Min(startpoint.X, e.X);
        drawtopleft.Y = Math.Min(startpoint.Y, e.Y);

        drawsize.Width = Math.Abs(startpoint.X - e.X);
        drawsize.Height = Math.Abs(startpoint.Y - e.Y);

        drawrect = new Rectangle(drawtopleft, drawsize);
        ((FlowLayoutPanel)sender).Refresh();

        pTransparent.Width = drawrect.Width;
        pTransparent.Height = drawrect.Height;
        pTransparent.Left = drawtopleft.X;
        pTransparent.Top = drawtopleft.Y;
        }
    }
}</pre>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2011/02/23/901/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# Windows form 透明 panel (transparent panel)</title>
		<link>http://blog.phanix.idv.tw/archives/2011/02/18/900/</link>
		<comments>http://blog.phanix.idv.tw/archives/2011/02/18/900/#comments</comments>
		<pubDate>Fri, 18 Feb 2011 09:43:22 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=900</guid>
		<description><![CDATA[using System.Windows.Forms; namespace XXX_namespace { /// /// A transparent control. /// public class TransparentPanel : Panel { public TransparentPanel() { } protected override CreateParams CreateParams { get { CreateParams createParams = base.CreateParams; createParams.ExStyle &#124;= 0x00000020; // WS_EX_TRANSPARENT return createParams; } } protected override void OnPaintBackground(PaintEventArgs e) { // Do not paint background. } } }]]></description>
			<content:encoded><![CDATA[<pre>using System.Windows.Forms;

namespace XXX_namespace
{
    ///
<summary>
    /// A transparent control.
    /// </summary>

    public class TransparentPanel : Panel
    {
        public TransparentPanel()
        {
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams createParams = base.CreateParams;
                createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
                return createParams;
            }
        }

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // Do not paint background.
        }
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2011/02/18/900/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DOS batch ADSL dial and disconnect</title>
		<link>http://blog.phanix.idv.tw/archives/2010/11/26/862/</link>
		<comments>http://blog.phanix.idv.tw/archives/2010/11/26/862/#comments</comments>
		<pubDate>Fri, 26 Nov 2010 11:56:53 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[網路應用]]></category>
		<category><![CDATA[電腦網路]]></category>
		<category><![CDATA[ADSL]]></category>
		<category><![CDATA[batch]]></category>
		<category><![CDATA[dos]]></category>
		<category><![CDATA[撥號]]></category>
		<category><![CDATA[自動撥號]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=862</guid>
		<description><![CDATA[把 ADSL 撥號跟斷線做成 Batch (.bat) 檔。 什麼時候可以用？當用浮動IP ADSL，想要跳IP掃網頁的時候。 @echo off rem 定義 ADSL 撥號名稱, ID, Password set adsl=預先設置號的ADSL撥號名稱 set adslid=YOUR_ID set adslpw=YOUR_PASSWORD :start rem 斷線 / disconnect Rasdial %adsl% /disconnect rem 撥號連線 / dial Rasdial %adsl% %adslid% %adslpw%]]></description>
			<content:encoded><![CDATA[<p>把 ADSL 撥號跟斷線做成 Batch (.bat) 檔。<br />
什麼時候可以用？當用浮動IP ADSL，想要跳IP掃網頁的時候。 <img src='http://blog.phanix.idv.tw/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<p><span id="more-862"></span></p>
<pre>@echo off
rem 定義 ADSL 撥號名稱, ID, Password
set adsl=預先設置號的ADSL撥號名稱
set adslid=YOUR_ID
set adslpw=YOUR_PASSWORD

:start
rem 斷線 / disconnect
Rasdial %adsl% /disconnect

rem 撥號連線 / dial
Rasdial %adsl% %adslid% %adslpw%</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2010/11/26/862/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Execute Batch file in Silent mode (no cmd window) / 以無 dos 命令列視窗執行 .bat</title>
		<link>http://blog.phanix.idv.tw/archives/2010/06/21/797/</link>
		<comments>http://blog.phanix.idv.tw/archives/2010/06/21/797/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 10:21:04 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[batch]]></category>
		<category><![CDATA[dos]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[程式設計]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=797</guid>
		<description><![CDATA[今天無意中看到正解，沒想到超簡單，不必用以前的蠢方法啦！ ----- without a window----- @echo off start /B Myapp.exe ---- minimized ---- @echo off start /MIN Myapp.exe]]></description>
			<content:encoded><![CDATA[<p>今天無意中看到正解，沒想到超簡單，不必用<a href="http://blog.phanix.idv.tw/archives/2009/06/29/701/" target="_blank">以前的蠢方法</a>啦！</p>
<pre>----- without a window-----
@echo off
start /B Myapp.exe

---- minimized ----
@echo off
start /MIN Myapp.exe</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2010/06/21/797/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# ActiveX Development, Deploying and Web Execution</title>
		<link>http://blog.phanix.idv.tw/archives/2010/05/30/785/</link>
		<comments>http://blog.phanix.idv.tw/archives/2010/05/30/785/#comments</comments>
		<pubDate>Sun, 30 May 2010 08:59:53 +0000</pubDate>
		<dc:creator>Phanix</dc:creator>
				<category><![CDATA[學習工作]]></category>
		<category><![CDATA[工作]]></category>
		<category><![CDATA[程式]]></category>
		<category><![CDATA[ActiveX]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[GUID]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[程式設計]]></category>

		<guid isPermaLink="false">http://blog.phanix.idv.tw/?p=785</guid>
		<description><![CDATA[最近在用 C# 開發 ActiveX 來擺在網頁上面執行，查了一些資料之後終於做出來了，來整理一下放在下面。 這次主要是要做兩個 ActiveX control，雖然介面類似但是功能不同，一個叫 FullControl，另一個叫做 TestControl。 建立User Control 跟過去用 MFC 或者用 VB 寫 ActiveX 有點不太一樣，在 .net 裡頭是用 User Control 來做出 ActiveX control，所以先在 VS 2005 裡頭開一個新的 User Control 的專案，然後把兩個 Control 加進去。 所以現在會有兩個檔案: FullControl.cs 跟 TestControl.cs。大概會長得類似下面這樣&#8230; namespace ActiveXTest { public partial class TestControl : UserControl { public TestControl() { InitializeComponent(); } //其他的程式碼 } [...]]]></description>
			<content:encoded><![CDATA[<p>最近在用 C# 開發 ActiveX 來擺在網頁上面執行，查了一些資料之後終於做出來了，來整理一下放在下面。</p>
<p><span id="more-785"></span></p>
<p>這次主要是要做兩個 ActiveX control，雖然介面類似但是功能不同，一個叫 FullControl，另一個叫做 TestControl。</p>
<h2>建立User Control</h2>
<p>跟過去用 MFC 或者用 VB 寫 ActiveX 有點不太一樣，在 .net 裡頭是用 User Control 來做出 ActiveX control，所以先在 VS 2005 裡頭開一個新的 User Control 的專案，然後把兩個 Control 加進去。</p>
<p>所以現在會有兩個檔案: FullControl.cs 跟 TestControl.cs。大概會長得類似下面這樣&#8230;</p>
<blockquote>
<pre>namespace ActiveXTest
{
    public partial class <span style="color:red;">TestControl</span> : UserControl
    {
        public TestControl()
        {
            InitializeComponent();
        }
        //其他的程式碼
    }
}</pre>
</blockquote>
<blockquote>
<pre>namespace ActiveXTest
{
    public partial class <span style="color:red;">FullControl</span> : UserControl
    {
        public TestControl()
        {
            InitializeComponent();
        }
        //其他的程式碼
    }
}</pre>
</blockquote>
<p>接下來就是製作需要的功能了，做好之後可以另外開一個 windows form project 來測試做好的 User Control 是否可以正常運作。</p>
<h2>讓這個 User Control 變成 COM 物件</h2>
<p>這是最重要的步驟!!</p>
<p>雖然 .net 做出來的 User Control 也是一個 .dll 檔，但是這跟過去用 VB 寫出來的一個 .ocx 或者 .dll，用 MFC 寫出來的一個 .dll 是截然不同的。</p>
<p>因為 ActiveX control 基本上是一個 com 物件，但是一般情況下 .net 做出來的 User control dll 並不是，所以我們要對 User Control 進行改造，使得這個 User Control 變成一個 COM 物件。</p>
<p>要變成 COM 物件首先我們需要建立這個 dll 的 COM Interface，所以要先幫 User Control 加上 IObjectSafty interface。</p>
<blockquote>
<pre>    [ComImport, GuidAttribute("<span style="color:red;">GUID</span>")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {

        [PreserveSig]
        int GetInterfaceSafetyOptions(ref Guid riid,
                      [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions,
                      [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);

        [PreserveSig()]
        int SetInterfaceSafetyOptions(ref Guid riid,
                      [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask,
                      [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
    }</pre>
</blockquote>
<p>要注意的是，因為現在 FullControl 跟 TestControl 都在同一個 namespace (ActiveXTest) 底下，所以這個 IObjectSafety interface 只要寫一個就好，看是寫在 FullControl.cs 或者 TestControl.cs 都可以。</p>
<p>而那個 GUID 的話可以用 GUID 工具產生，它放在 VS 2005 的 &#8220;工具&#8221; &#8211;> &#8220;建立GUID&#8221;。如果沒有這工具的話可以用 &#8220;外部工具&#8221; 來新增這個工具，預設路徑是在 C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\guidgen.exe 。產生的 Interface 可能像下面這樣:</p>
<blockquote>
<pre>namespace ActiveXTest
{    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
    ...
    }
}
</pre>
</blockquote>
<p>寫好 Interface 之後接著就是需要 implement 這個 interface 中的 methods，所以兩個 User Control 都需要繼承這個 interface&#8230;</p>
<blockquote>
<pre>namespace ActiveXTest
{
    public partial class TestControl : UserControl, <span style="color:red;">IObjectSafety</span>
    {
    ...
    }

    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
    ...
    }
}
</pre>
</blockquote>
<blockquote>
<pre>namespace ActiveXTest
{
    public partial class FullControl : UserControl, <span style="color:red;">IObjectSafety</span>
    {
    ...
    }

    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
    ...
    }
}
</pre>
</blockquote>
<p>而怎麼 implement int GetInterfaceSafetyOptions() 跟 int SetInterfaceSafetyOptions() 呢？直接去 <a href="http://www.pinvoke.net/default.aspx/Interfaces/IObjectSafety.html" target="_blank">pinvoke.net</a> 這邊去抄 :p</p>
<p>接下來也要給 User Control 一個 GUID，要不然也空有 Interface 但不知道 ActiveX control 實際的 GUID 的話也是不行的。</p>
<blockquote>
<pre>namespace ActiveXTest
{
    <span style="color:red;">[Guid ("9551B223-6188-4387-B293-C7D9D8173E3A")]
    [ProgId("ActiveXUpload.TestControl")]
    [ComVisible(true)]</span>
    public partial class TestControl : UserControl, <span style="color:red;">IObjectSafety</span>
    {
    ...
    }

    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
    ...
    }
}
</pre>
</blockquote>
<blockquote>
<pre>namespace ActiveXTest
{
    <span style="color:red;">[Guid ("9551B223-6188-4387-B293-C7D9D8173E3A")]
    [ProgId("ActiveXUpload.FullControl")]
    [ComVisible(true)]</span>
    public partial class FullControl : UserControl, IObjectSafety
    {
    ...
    }

    [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
    ...
    }
}
</pre>
</blockquote>
<p>這樣子就已經差不多了，但是在建置之前必須要設定一下 project 的屬性，把「註冊為 Com Interop」選項勾選起來。另外還要把這個專案作簽署，就是把專案屬性的簽署組件勾選起來。這樣子，建置之後應該會有 .dll 以及一個 .tlb (typed library)，其實到這邊就可以把 ActiveX 的 DLL 拿來用了，可是這時候如果要在網頁上面使用這個 ActiveX 的話，要做一大堆的設定，所以，還是乖乖地包裝成 CAB 吧。</p>
<h2>建立 ActiveX 自動安裝專案</h2>
<p>要建立 ActiveX 的 CAB 時，需要 Cabarc.exe，這個tool在 VS 2005 裡頭就會有了，預設的話會在 C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin 裡頭。要不然也可以在 Microsoft 下載中心去下載 <a href="http://www.microsoft.com/downloads/details.aspx?displaylang=zh-tw&#038;FamilyID=49ae8576-9bb9-4126-9761-ba8011fabf38" target="_blank">Windows XP Service Pack 2 支援工具</a>，雖然在 Windows 的 server 版本中無法安裝，但是可以用 winrar 來解壓縮把 cabarc.exe 拿出來用。</p>
<p>如果不想要去下載 XP 支援工具的話，還是有方法可以解決的。首先還是先在 VS 2005 裡頭作一個安裝的專案，然後就可以產生出一個 .msi 跟一個 setup.exe 檔案。但接下來的我們只需要 .msi，這也是為什麼我們不直接建立一個 CAB 封裝的專案，而是先建立一個自動安裝的專案。</p>
<h2>建立 ActiveX 的 CAB 封裝</h2>
<p><del datetime="2010-06-01T06:37:08+00:00">接下來在 VS 2005 裡頭建立一個 CAB 封裝專案，</del>(請直接看最下方的紅色文字部分補充說明) 然後加入前一個步驟的 .msi 檔案，以及一個 install.inf 檔案，比方說下面這樣：</p>
<blockquote><p>
[version]<br />
signature=&#8221;$CHICAGO$&#8221;<br />
AdvancedINF=2.0</p>
<p>[Setup Hooks]<br />
hook1=hook1</p>
<p>[hook1]<br />
run=msiexec.exe /i &#8220;%EXTRACT_DIR%\ActiveXTest.msi&#8221; /qn
</p></blockquote>
<p>Signature 的值可以是 $Windows NT$, $Windows 95$, $Chicago$。其中 $Windows NT$ 為NT系列專用，$Windows 95$ 為 windows 9x系列專用，而 $Chicago$ 是除了WIN3X以下系統其他WIN系統都可以用，所以當然是用 $Chicago$ 囉。產生出 cab 之後就可以在網頁上使用了。</p>
<p>如果要把 install.inf 寫得更好一點的話可以寫成類似下面這樣：</p>
<blockquote><p>
[Setup Hooks]<br />
hook.mycontrol=hook.mycontrol</p>
<p>[Add.Code]<br />
mycontrol.dll=mycontrol.dll</p>
<p>[mycontrol.dll]<br />
CLSID={50894390-9cb3-4a6d-bb40-b786b7e9548d}<br />
FileVersion=1,1,0,3<br />
hook=hook.mycontrol</p>
<p>[hook.mycontrol]<br />
run=msiexec.exe /i %EXTRACT_DIR%\mycontrol.msi /qn</p>
<p>[Version]<br />
; This section is required for compatibility on both Windows 95 and Windows NT.<br />
Signature=&#8221;$CHICAGO$&#8221;<br />
AdvancedInf=2.0
</p></blockquote>
<p>如果想要讓這個 CAB 做得更完美一點的話，還可以對這個 CAB 作簽章。這時候要用到 signtool.exe ，也是放在 C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin 裡面。使用 signtool.exe wizard 之後就會彈出視窗來做簽署動作。</p>
<p><span style="color:red;">Jun. 1, 2010: 經過反覆測試發現，還是用 Cabarc.exe 自己來包 .cab 比較好一點。只要用 <i>cabarc.exe N ActiveXTest.cab ActiveXTest.msi install.inf</i> 這樣的指令就可以了。如果用 VS 2005 的 CAB 專案，則會在產生出來的 .cab 檔案中多一個 xxx.OSD 這樣的一個 OSD (open source description) 檔案，而導致在使用這個 activex cab 包的時候發生錯誤無法正確安裝。</span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.phanix.idv.tw/archives/2010/05/30/785/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

