2009年7月30日 星期四

製作HTML Help

XML的文件轉成類似MSDN Help(*.CHM檔)的工具有很多, 早期是使用NDoc(它是Open Source)
不過後來在 NDoc 1.3.1 版後,NDoc 的作者就不再進行程式的開發, 所以NDoc只支援.NET 2.0之前的平台.

後來微軟推出SandCastle 來取代NDoc, 不過SandCastle要使用命令列來製作Help文件, 對於習慣用UI操作的人會嫌太麻煩, 因此, 就有DocProject , Sandcastle Help File Builder, SandcastleGUI 等UI工具出現.

網路上也有人寫了這些工具相關教學, 如下所示:

使用DocProject產生.NET物件文件


SandCastle 的安裝及使用

使用 Sandcastle Help File Builder 製作 VS.NET 的 HELP 文件



這三套軟體, 我都有下載, 安裝來玩玩看, 使用後的心得, 我個人是比較喜歡使用DocProject, 因為它和Visual Studio的介面有作整合, 而且在操作上也比較簡單.


[圖 1] DocProjectVisual Studion上的專案



[圖 2] DocProject產生的說明文件

2009年7月29日 星期三

C#使用XML註解

我相信progrmmer都有類似的經驗, 就是一兩個月之前寫的code, 日後在閱讀時, 如果沒有特別加上註解, 就要花腦筋和時間去回想, 當初code為何這樣寫, 嚴重一點的話, 甚至可能忘記當初的思路和流程.

因此,
在程式碼加上註解是很重要的事, 因為它可以提高程式的可讀性和清晰度, 可方便日後程式碼的維護.

寫註解的方式, 最基本的寫法, 就是在註解說明之前加上//, 或把註解內容放在/* */
之間,如下所示:

// This is a comment

/*
This is a comment */

除了基本的寫法外, 你也可以用以XML為基礎的註解說明, 使用XML的好處是, 它是通用的資料格式, 易於作數據交換; 另外, 它可表達出結構化的資料. 而且還可以透過一些工具, 自動產生類別庫的參考手冊.


本文先介紹, 如何在C#程式碼中, 撰寫XML的註解說明, 下一篇文章再來介紹, 可以將XML檔自動轉成HTML help文件(類似MSDN help的說明文件)的工具.

XML參考文件的撰寫方式,是以///符號開頭, 並連接一個 XML 文件標籤(tag) , 標籤的名稱說明該段註解的目的. 下面的表格列出, 常用的XML標籤和說明.



XML標籤 說明
<summary> 摘要性的描述
<remark> 詳細的註解說明
<example> 使用範例, 通常<example>標籤中, 經常會包含多個<code>標籤
<code> 標示程式碼,被<code>標示住的程式碼,會和說明文件的一般文字不同格式
<c> 標示包含在一般文字段落中的程式碼
<see cref ="member"> 在產生的說明文件中, 產生一個連接到其他成員的超連結
<seealso cref ="member"> 和<see>標籤的功能差不多, 不過在說明文件中,<seealso>標籤會獨立到另一個區域作顯示
<exception> 說明程式丟出的異常
<param> 說明函式(method)的參數
<return> 說明函式(method)的回傳值
<value> 說明屬性(property)



若你想知道更詳細的內容, 可以到MSDN的XML Documentation的線上說明去查看.

下面的範例程式碼, 介紹XML說明文件的撰寫方式, 我們不要管程式碼的內容, 只要注意XML註解的寫法.


// XMLDocSample.cs
using System;

/// <summary>
/// Class level summary documentation goes here.
/// </summary>
/// <remarks>
/// Longer comments can be associated with a type or member
/// through the remarks tag
/// </remarks>
public class SomeClass
{
/// <summary>
/// Store for the name property
/// </summary>
private string myName = null;

/// <summary>
/// The class constructor.
/// </summary>
public SomeClass()
{
// TODO: Add Constructor Logic here
}

/// <summary>
/// Name property
/// </summary>
/// <value>
/// A value tag is used to describe the property value
/// </value>
public string Name
{
get
{
if (myName == null)
{
throw new Exception("Name is null");
}

return myName;
}
}

/// <summary>
/// Description for SomeMethod.
/// </summary>
/// <param name="s">
/// Parameter description for s goes here
/// </param>
/// <seealso cref="String">
/// You can use the cref attribute on any tag to reference a type or member
/// and the compiler will check that the reference exists.
/// </seealso>
public void SomeMethod(string s)
{
}

/// <summary>
/// Some other method.
/// </summary>
/// <returns>
/// Return results are described through the returns tag.
/// </returns>
/// <seealso cref="SomeMethod(string)">
/// Notice the use of the cref attribute to reference a specific method
/// </seealso>
public int SomeOtherMethod()
{
return 0;
}

}


加上註解後, 開啟VC 2008 專案的Properties 視窗, 選擇Build , 然後勾選XML documentation file, 即可在build之後, 產生一份XML的文件.

[圖 1] VC專案Build的設定




[圖 2] XML檔的內容

2009年7月22日 星期三

人性化操作介面(Natural User Interface) = WPF + Multi-Touch

iPhone的成功因素之一, 是因為它改變User操作介面的習慣(滑鼠or鍵盤), 它採用多點觸控(Multi-touch)和手勢(Gesture)操作來實現UI的使用, 這樣能更直覺也更人性化, 因此能觸動人心. 而這也造成未來產品UI設計和操作上的一些轉變, 必定會往人性化操作介面(Natural User Interface)的概念前進.


[圖] iPhone的操作介面


當然不讓Apple專美於前. 微軟Visual Studio 2010上的WPF 4中, 也提供多點觸控的控制項 (Multi-touch Control), 讓使用者設計出更多人性化的操作介面.

下面列出 Microsoft .NET Framework 4 Beta 1 中關於 WPF支援Multi-touh的項目:

Improvements in WPF:
  • Added support in Windows Presentation Foundation (WPF) for Windows 7 multi-touch, ribbon controls, and taskbar extensibility features.
  • Added support in WPF for Surface 2.0 SDK.


下面是相關影片的連結:

How to do Multitouch with WPF4 in VS2010




What's New in Windows Presentation Foundation 4



軟硬體的需求如下:

另外, 順便一提, 有一個叫作 NUI (Natural User Interface)團體, 裡面的人在推廣多點觸控的介面, 而且還完全公開他們軟體的程式碼和硬體的技術, 在這網站中, 你可以獲得很多關於Multi-Touch的相關知識.

2009年7月20日 星期一

利用WPF製作Gadget

利用WPF產生一個Transparency Window或是Non-Rectangular Window , 還滿簡單做到, 因此, 你可以很容易製作出一些桌面上的小工具(Gadget).


[圖] 手機Gadget

資料來源:
CodeProject - 3D gadgets for your WPF Desktop


下面步驟說明如何製作一個小
Gadget. 首先, 產生一個WPF Windows Application的專案. 然後, 修改Window Property.

1. Background = Transparent
背景顏色要設成透明色




2. AllowsTransparency = True
如果
AllowsTransparencyFalse的話, Window Background將只會被設成黑色.



3. Window Style = None
將視窗樣式設定成沒有邊框.



如果不這麼做的話, 執行此程式後, 會出現一個Exception. 告訴你當AllowsTransparency為True時,WindowStyle必須為True





部分XAML檔如下所示:

"http://schemas.microsoft.com/winfx/2006/xaml/presentation"
WindowStyle="None"
AllowsTransparency="True"
Background="Transparent">
...


4. Mouse drag
如果要用滑鼠移動透明視窗, 必須另外加入Mose Event.

在XAML檔中加入
MouseLeftButtonDown="Window_MouseLeftButtonDown"

點選C#檔,Window_MouseLeftButtonDown函式中, 加入下面程式碼(在視窗上點選滑鼠左鍵,可拖曳此視窗)

private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}


5. Close Application
在視窗呈現完全透明情況下,視窗的非工作區的一些選項 ([關閉] 功能表、[最小化]、[最大化] 和 [還原] 按鈕等等) 就無法使用, 因此, 如果要關閉視窗, 就需要額外設計一個close的button.

Close Button的XAML檔如下所示:


<button dock="Right" margin="5" height="Auto" width="37" name="button1" click="button1_Click" verticalalignment="Center" background="Red" foreground="White" fontsize="16">X</button>



點選C#檔, 在
button1_Click函式中, 加入下面程式碼(點選關閉的button後, 關閉此視窗)

private void button1_Click(object sender, RoutedEventArgs e)
{
this.Close();
}


執行結果如下所示:


[NOTE]如果你想要此Gadget不要出現Taskbar, 可以作以下的設定:
ShowInTaskbar="False" Topmost="True"


2009年7月17日 星期五

WPF 入門

什麼是WPF? WPF是"Windows Presentation Foundation"的縮寫, 它是.NET 3.0(NET 3.0 = WPF+WF+WCF+CardSpace+NET 2.0)內含的一項機制; 主要是UI的呈現. WPF最大的特色是能作出酷炫的UI(如Windows Vista上生動的介面與外觀設計), 如果你不想再用傳統的MFCWindows Form來設計應用程式, 使用WPF是個很好的選擇.


[圖 1] WPF 介面能整合影像、文字、2D圖形、3D圖形等



[圖 2] Custom UI Control



[圖 2] Document Viewer



[圖 3] Animation



[圖 4] Media Player



[圖 5] 2D Drawing




[圖 6] 3D Model


Cool WPF applications網站有很多很酷WPF應用程式:



當然, 除了能作出很棒的UI之外, WPF還有很多特色, 如下所示:

1. 廣泛的整合 -
Before: 學習不同的技術和API
WPF:
內建的支援技術整合2D,3D繪圖, 影片, 語音, 數位文件等

2. 與解析度無關-

Before : 元素放大時, 影像會失真
WPF :使用向量化圖形, 影像不失真


3. 硬體加速-
WPF 圖形系統是專門設計為利用圖形硬體來將 CPU 使用率降至最低


4. 宣告示程式設計方法-
Before : 寫程式碼或在資源檔建構控制項
WPF: 利用XAML定義UI,數位文件, 3D模型;
讓程式設計人員能和其他領域的專家共事; Application = Code + Markup

5. 豐富的組合和自定能力
-
Before : 實作上相對困難, 要修改resource,或Overwrite class 或 function

WPF : 容易地換掉整個應用程式的"面板(Skin)"

總而言之; WPF結合Directx(3D及硬體加速), Windows Form(控制項建立), Adobe Flash(動畫支援), 及HTML(宣告示標記和簡單的部署)

參考資料 : MSDN - Windows Presentation Foundation 簡介


Windows 7 Touch SDK - WM_GESTURE Message


本文章出自: MSDN- WM_GESTURE Message

WM_GESTURE Message

目的

傳送手勢訊息

參數

wParam


lParam
提供手勢資訊的handle, 可以利用GetGestureInfo 函式來取得相關的資料(包含手勢的類型, 參數, 作用點...等)

回傳值

如果程式可以處理WM_GESTURE的訊息, 回傳值為0.

假使程式不能處理此訊息, 你必須呼叫 DefWindowProc來處理系統內定的訊息. 如果不那麼作的話, 可能會導致記憶體遺漏(Memory Leak), 因為touch unout handle將沒有被關掉, 因此Process中開啟的touch input handle記憶體也沒被釋放.


Remarks

下面表格列出Window Touch SDK支援的手勢:

Gesture IDValue (dwID)Description
GID_BEGIN1
一個手勢開始發生

GID_END2
一個手勢結束

GID_ZOOM3

放大, 縮小或縮放動作開始. 第一個GID_ZOOM訊息表示ZOOM開始, 但是還不會造成任何ZOOM的動作, 當程式收到第二個GID_ZOOM訊息時, 才會去觸發(trigger) ZOOM.

GID_PAN4
平移或平移動作開始. 第一個GID_PAN訊息表示PAN開始, 但是還不會造成任何PAN的動作, 當程式收到第二個GID_PAN訊息時, 才會去觸發PAN.

GID_ROTATE5

旋轉或旋轉動作開始. 第一個GID_ROTATE訊息表示ROTATE開始, 但是還不會造成任何ROTATE的動作, 當程式收到第二個GID_ROTATE訊息時, 才會去trigger ROTATE.


GID_TWOFINGERTAP6
兩手指敲碰(tap)觸控螢幕

GID_PRESSANDTAP7第一根手指按壓(press)在觸控螢幕上, 另一根手指作tap


下面的表格標示出手勢的參數(gesture arguments)

Gesture IDGestureullArgumentptsLocation
GID_ZOOMZoom In/Out兩個觸控點之間的距離

兩個觸控點的中心

GID_PANPan兩個觸控點之間的距離

Pan手勢目前的作用點



GID_ROTATERotate (pivot)
假如GF_BEGIN的旗標被設定, ullArgument表示旋轉角度(初始的角度為絕對角度), 如果為其他旗標 , ullArgument表示相對的角度(目前的角度 - 初始角度), 其角度的值會有正負號, 代表的式旋轉方向你可以使用GID_ROTATE_ANGLE_FROM_ARGUMENTGID_ROTATE_ANGLE_TO_ARGUMENT 來取得角度的值

為旋轉中心點(即固定不動的點)


GID_TWOFINGERTAP
Two-finger Tap
兩個觸控點之間的距離
兩根手指之間的中心點.

GID_PRESS_AND_TAP
Press and Tap
兩根手指之間的距離第一根手指按壓在觸控螢幕上的接觸點

2009年7月13日 星期一

在blog中顯示程式碼區(code block)

若在blog中貼上一段程式碼, 往往會不容易閱讀, 這裡來介紹如何作一個程式碼的區塊.

資料來源:http://chenkaie.blogspot.com/2006/11/css-cool-blockquote-for-code-style.html

1. 修改版面配置
到"修改版面配置"選擇"修改HTML", 如下圖所示:




2. 加上code{}語法
在body{}之後, 加上以下語法

code {
display: block; /* fixes a strange ie margin bug */
font-family: Courier New;
font-size: 9pt;
overflow:auto;
background: #fff5ee url(http://sites.google.com/a/hc888.com.tw/file/img/Code_BG0.gif) left top repeat-y;
border: 1px solid #ccc;
padding: 5px 5px 5px 20px;
max-height:200px;
line-height: 1.2em;
margin: 5px 0 0 15px;
}

3. 在文章中使用code語法
因此若要使用<code> tag,方法如下
<code>程式碼放置處</code>


如下面範例所示:

namespace WpfApplication1
{
///
/// Interaction logic for Window1.xaml
///
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}

2009年7月12日 星期日

Windows 7 Touch SDK - TOUCHINPUT Structure


本文章: MSDN-TOUCHINPUT Structure

TOUCHINPUT Structure

目的

觸控輸入的資料結構

語法

typedef struct _TOUCHINPUT {
LONG x;
LONG y;
HANDLE hSource;
DWORD dwID;
DWORD dwFlags;
DWORD dwMask;
DWORD dwTime;
ULONG_PTR dwExtraInfo;
DWORD cxContact;
DWORD cyContact;
} TOUCHINPUT, *PTOUCHINPUT;

成員

x
觸控點的x座標, 可以呼叫TOUCH_COORD_TO_PIXEL() 將觸控座標轉換成像素

y

觸控點的y座標, 可以呼叫TOUCH_COORD_TO_PIXEL() 將觸控座標轉換成像素

hSource
來源裝置的handle.

dwID
觸控點的ID

dwFlags
觸控點的flag; 用來標示觸控點被按壓, 釋放或移動. 類似操作滑鼠的行為

dwMask
一個可以修改的flag, 此flag可以判斷是否支援觸控點的面積.

dwTime
觸控事件的作用時間, 單位為毫秒.


dwExtraInfo
一個額外的數值和touch event有相關

cxContact
觸控點接觸面積的寬. 這個值僅有在dwMask TOUCHEVENTFMASK_CONTACTAREA時, 才有作用.

cyContact

觸控點接觸面積的高. 這個值僅有在dwMask TOUCHEVENTFMASK_CONTACTAREA時, 才有作用.

Remarks

下面的表格列出dwFlag的型態

FlagValueDescription
TOUCHEVENTF_MOVE0x0001
觸控點開始移動.

TOUCHEVENTF_DOWN0x0002
觸控點被建立, 例如手指或觸控筆按壓螢幕.

TOUCHEVENTF_UP0x0004觸控點被移除, 例如手指或觸控筆離開螢幕.
TOUCHEVENTF_INRANGE0x0008
一個觸控點在範圍內. 這個flag可以用來啟動touch hover(如果硬體有支援). 如果應用程式不想要hover可以忽略此flag

TOUCHEVENTF_NOCOALESCE0x0020
When received using GetTouchInputInfo, this input was not coalesced.

TOUCHEVENTF_PALM0x0080
觸控的事件來自於使用者的手掌

TOUCHEVENTF_PRIMARY0x0010標示出第一個(primary)觸控點.

Note 如果你的觸控裝置不支援hover; 當TOUCHEVENTF_UP flag被設定時,TOUCHEVENTF_INRANGE 會被清除. 如果觸控裝置有支援hover, TOUCHEVENTF_UP and TOUCHEVENTF_INRANGE會被獨自設定.

The following table lists the flags for the dwMask member.

FlagValueDescription
TOUCHINPUTMASKF_CONTACTAREA0x0004
有提供cxContactcyContact.

TOUCHINPUTMASKF_EXTRAINFO0x0002
有提供 dwExtraInfo


TOUCHINPUTMASKF_TIMEFROMSYSTEM

0x0001

系統的時間設定在 TOUCHINPUT 結構中.

2009年7月10日 星期五

程式語言的演變

這個世界已經變成瞬息萬變的時代, 尤其在軟體世界,
要學習的東西真的很多. 當你開始學習某種語言, 幾年後已經熟練它,可以出師時,
偏偏它已經開始沒落,快被另一種語言取代. 這時你又必須再學習另一套語言.

還記得剛開始寫程式時,是從最基本的C開始學起, 後來物件導向(OOP)的觀念開始流行時,
就要學習C++和OOP, 為了要優化OOP和結構化程式碼, 你也得必須了解Design Pattern(軟體設計模式)和UML(統一塑模語言),
前幾年微軟開始推展.NET Framework後, 還得學習CLR(共通語言執行平台)和C#

而在GUI(Graphical User Interface,圖形使用者介面)上的改變,
從早期Windows API(
視窗作業系統應用程式介面),
MFC(Microsoft Foundation Classes;以C++類的形式封裝了Windows的API),

再來就是.NET的Windows Form,
近年來還出現XAML的WPF(Windows Presentation Foundation;.NET 3.0內含的一項機制,內建的支援技術整合2D,3D繪圖, 影片, 語音, 數位文件等)

而這些還只是開發Windows application時要學習的東西,
只能說現在的程式設計人員要學的東西真的很多,
當然; 我覺得基本功是最重要的(也就是基本的C語言+物件導向),

只要馬步紮穩, 要學習任何東西應該都很快.

在MFC中使用OpenGL

這篇文章介紹如何在MFC上使用OpenGL.

1. 產生一個MFC Dialog, 然後引用OpenGL的標頭檔(gl.h, glu.h), 和連結OpenGL的函式庫(opengl32.lib, glu32.lib); 其作法可參考在Windows中使用OpenGL

2. 在ClassWizard增加WM_CREATE訊息處理OnCreate
函式(設定OpenGL RC);


部分程式碼所下所示:

int CMFC_OpenGLDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;

// TODO: Add your specialized creation code here

//取得一個DC
m_hDC = ::GetDC(this->GetSafeHwnd());
//調整這個DC的像素格示
if(!SetPixelformat(m_hDC))

{
::MessageBoxA(::GetFocus(),"SetPixelformat Failed!","Error",MB_OK);
return -1;

}

//產生一個OpenGL rendering context
m_hGLRC = wglCreateContext(m_hDC);

//
設置為當前的RC
m_hDC, m_hGLRC); InitGL();
return 0;
}



3.
增加WM_SIZE訊息處理OnSize函式(改變ViewPort)

void CMFC_OpenGLDlg::OnSize(UINT nType, int cx, int cy)
{
CDialog::OnSize(nType, cx, cy);

// TODO: Add your message handler code here
GLsizei width;
GLsizei height;

width = cx;
height = cy;

ReSizeGLScene((GLsizei) width, (GLsizei) height);
}

GLvoid CMFC_OpenGLDlg::ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{

if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}

glViewport(0,0,width,height); // Reset The Current Viewport

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix

// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix

}



4. 增加WM_PAINT訊息處理OnPaint函式(將繪圖函式加在裡面)

void CMFC_OpenGLDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);

// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{

DrawGLScene();
SwapBuffers(m_hDC);


CDialog::OnPaint();
}
}


int CMFC_OpenGLDlg::DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0

glBegin(GL_TRIANGLES); // Drawing Using Triangles
glColor3f(1.0f,0.0f,0.0f); // Set The Color To Red
glVertex3f( 0.0f, 1.0f, 0.0f); // Top
glColor3f(0.0f,1.0f,0.0f); // Set The Color To Green
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glColor3f(0.0f,0.0f,1.0f); // Set The Color To Blue
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glEnd(); // Finished Drawing The Triangle
glTranslatef(3.0f,0.0f,0.0f); // Move Right 3 Units
glColor3f(0.5f,0.5f,1.0f); // Set The Color To Blue One Time Only
glBegin(GL_QUADS); // Draw A Quad
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right
glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
glEnd(); /// Done Drawing The Quad

return TRUE; // Keep Going
}


5. 增加WM_DESTROY訊息處理OnDestory函式(釋放不用的DCRC)


void CMFC_OpenGLDlg::OnDestroy()
{
CDialog::OnDestroy();
wglMakeCurrent(NULL,NULL);
wglDeleteContext(m_hGLRC);
}


結果如下面圖式:

2009年7月8日 星期三

Windows 7 Touch SDK - WM_TOUCH, GetTouchInputInfo

WM_TOUCH Message

目的

通知視窗當有一個或多個觸控點(例如手指頭或觸控筆)作用在觸控螢幕上

參數

wParam
包含觸控點的數目

lParam
包含一個觸控輸入的handle, 可以呼叫GetTouchInputInfo來取得更詳細的資料.

注意: 當應用程式不再需要此handle時, 必須呼叫CloseTouchInputHandle去釋放這個handle的記憶體, 如果不這麼做的話, 可能會造成memory leak.

傳回值

如果此應用程式能處理此訊息,回傳為0. 如果不能處理此訊息, 必須呼叫 DefWindowProc. 不那麼作的話, 可能造成記憶體遺失(memory leak) , 因為touch input handle 沒被關掉.



GetTouchInputInfo Function

目的
取得觸控輸入的詳細資訊


語法


BOOL WINAPI GetTouchInputInfo(
__in HTOUCHINPUT hTouchInput,
__in UINT cInputs,
__out PTOUCHINPUT pInputs,
__in int cbSize
);

參數

hTouchInput [in]
傳入一個觸控輸入的handle(可以從觸控訊息的 LPARAM取得)


cInputs [in]

傳入觸控輸入資料結構的數目(可以從觸控訊息WPARAM取得); 此數目會等於觸控點的數目.

pInputs [out]

取得TOUCHINPUT的指標(TOUCHINPUT* ti)


cbSize [in]

一個TOUCHINPUT structure的大小, 可寫成sizeof(TOUCHINPUT)

傳回值

如果此函式可以取得參數, 回傳值不為0. 如果失敗, 則返回0

註解

使用CloseTouchInputHandle將不能釋放TOUCHINPUT指標的記憶體, 必須要自行delete此memory, 如下所示:

CloseTouchInputHandle((HTOUCHINPUT)lParam);
delete [] ti;

參考資料: MSDN - Windows Touch Input



Windows 7 Touch SDK - RegisterTouchWindow, UnregisterTouchWindow, IsTouchWindow

之前寫了兩篇關於介紹Touch InputGesture的函式定義, 都太於戎長, 所以我將這些文章刪掉, 重新慢慢整理, 希望對有用到的人有幫助.

RegisterTouchWindow Function

目的

將一個視窗註冊成有觸控功能

語法


BOOL WINAPI RegisterTouchWindow(
__in HWND hWnd, __in ULONG ulFlags
);

參數

hWnd [in]

傳入一個window handle(需要註冊有觸控功能), 通常為HWND的型態

ulFlags [in]
傳入一個可修改的flag, 預設設定成0就好了

傳回值

如果註冊成功的話, 回傳值不為0; 如果註冊失敗, 回傳值為0. 要得到額外的錯誤資訊, 我們可以使用GetLastError函式來取得

註解

注意: RegisterTouchWindow 必須在每個需要用到觸控輸入(touch input)的視窗上作註冊, 也就是說如果有一隻應用程式具有多個視窗, 你必須要在每個需要控功能的視窗上作註冊. 當一個視窗不在需要觸控功能時, 呼叫 UnregisterTouchWindow來取消觸控輸入.


UnregisterTouchWindow Function

目地

將視窗註冊成不再有觸控功能

語法


BOOL WINAPI UnregisterTouchWindow(

__in HWND hWnd
);

參數

hWnd [in]
傳入一個window handle(註冊不再有觸控功能), 通常為HWND的型態

傳回值

如果註冊成功的話, 回傳值不為0; 如果註冊失敗, 回傳值為0. 要得到額外的錯誤資訊, 我們可以使用GetLastError函式來取得



IsTouchWindow Function

目地

檢查一個指定的視窗是否有觸控功能

語法

BOOL WINAPI IsTouchWindow(
__in HWND hWnd,
__out_opt PULONG pulFlags
);

參數

hWnd [in]

傳入一個window handle 通常為HWND的型態.

pulFlags [out, optional]
回傳一個 flag(此flag為之前呼叫RegisterTouchWindow函式, 所傳入的flag)

傳回值

如果此視窗支援觸控功能為TRUE, 如果不支援觸控功能為FALSE.


參考資料:MSDN- Windows Touch Input



2009年7月6日 星期一

在Windows中使用OpenGL

若你是OpenGL的初學者, 你可以透過GLUT(OpenGL Utility Toolkit)函式庫來撰寫3D程式, GLUT會對視窗的功能和顯示作包裝, 讓user可以不用接觸到Windows的東西, 進而簡化學習OpenGL的步驟. 但是如果你是想在Win32, MFC或Windows Form上使用OpenGL, 就必須在視窗上另外作一些設定, 這篇文章介紹, 如何在Win32 Window上使用OpenGL API.

1. 編譯環境設定
a. 連結 OpenGL 函式庫, 在 Visual C++ 的 Project, Setting 中, 點選 Linker. 加上 OpenGL32.lib GLu32.lib, 如下圖所示:


b. 引用OpenGL標頭檔
// Include OpenGL header file
#include <gl\gl.h>
// Header File For The OpenGL32 Library
#include <gl\glu.h> // Header File For The GLu32 Library


2. 修改WNDCLASS和CreateWindowEx的style

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{

WNDCLASS wc;
MSG uMsg;

memset(&uMsg, 0, sizeof(uMsg));

//下面程式碼中, 我們抓到視窗的 instance, 然後就定義視窗類別

g_hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window

wc.lpszClassName = "MY_WINDOWS_CLASS";

//CS_HREDRAW 和 CS_VREDRAW 是用來強迫視窗在改變大小時要重新繪製. CS_OWNDC
//為視窗建立私有的 DC. 也就是指 DC 不能被別的應用程式所共用

wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.hInstance = g_hInstance;
wc.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_WIN32GL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
if( !RegisterClass(&wc) )
return E_FAIL;

g_WinWidth = 1280;
g_WinHeight = 800;

//建立視窗
g_hWnd = CreateWindowEx( NULL,
"MY_WINDOWS_CLASS",
"OpenGL Win32 Window",
//我們在視窗形式上設了 WS_CLIPSIBLINGS 和 WS_CLIPCHILDREN.
//WS_CLIPSIBLINGS 和 WS_CLIPCHILDREN 是必須要的, 這樣 OpenGL 才能
//正常運作. 這些形式的設定可以避免別的視窗畫到我們的 OpenGL 視窗上.
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, g_WinWidth, g_WinHeight,
NULL,
NULL,
g_hInstance,
NULL );

if( g_hWnd == NULL )
return E_FAIL;

ShowWindow(g_hWnd, nCmdShow);
UpdateWindow(g_hWnd);

....................
}



3.使用OpenGL Rendering Context
基本上分成下面幾個步驟:

a. 先取得一個DC(Device Context); 開始在視窗繪圖之前, 一定要有一個Windows Device Context; Windows下的任何繪圖(即時繪製到記憶體內的bitmap)都需要DC以識別被繪製的物件.
b. 調整這個
DC的像素格示(PixelFormat)讓OpenGL進行繪製
c. 用wglCreateContext(hDC)去得到RC(OpenGL的著色區)
d.
wglMakeCurrent(hRC,hDC)將剛才建立的RC變成目前的RC

部分程式碼如下所示:


BOOL CreateGLWindow(int WinWidth, int WinHeight)
{
// 每一個 OpenGL 程式都要連結到一個著色區. 著色區就是連結到 OpenGL 的裝置內容 (Device Context). OpenGL 的著色區定義為 hRC. 為了將你的程式畫到視窗上, 你必須建立一個裝置內容(Device Context). 視窗的裝置內容 (Device Context) 定義為 hDC. 這個 DC 連接到視窗的 GDI (圖形裝置介面). RC 連接 OpenGL 到 DC.

if (!(g_hDC = GetDC(g_hWnd))) // Did We Get A Device Context?
{
KillGLWindow();
MessageBoxA(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}

if(!SetupPixelFormat(g_hDC))
{
KillGLWindow();
return FALSE;
}

if (!(g_hRC = wglCreateContext(g_hDC))) // Are We Able To Get A Rendering Context?
{
KillGLWindow(); // Reset The Display
MessageBoxA(NULL,
"Can't Create A GL Rendering Context.",
"ERROR",MB_OK|MB_ICONEXCLAMATION);

return FALSE;
}

if(!wglMakeCurrent(g_hDC,g_hRC)) // Try To Activate The Rendering Context
{
KillGLWindow();

MessageBoxA(NULL,
"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

ReSizeGLScene(WinWidth, WinHeight); // Set Up Our Perspective GL Screen

if (!InitGL()) // Initialize Our Newly Created GL Window
{

KillGLWindow(); // Reset The Display
MessageBoxA(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
return TRUE;

}



SetupPixelFormat的程式碼如下所示:

// The pixel format is an extension to the Win32 API that is provided for support of OpenGL functionality.

BOOL SetupPixelFormat(HDC hDC)
{
int nPixelFormat;

//這一段程式碼描述一個圖素的格式. 我們選擇一個格式支援 OpenGL 和雙緩衝區, 在 RGBA (紅,綠, 藍, 透明) 狀態. 並且找一個圖素格式符合所選的色彩位元數 (16bit,24bit,32bit). 最後設定 16bit的 Z-緩衝區.

static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of structure.
1, // always 1.
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGl
PFD_DOUBLEBUFFER, // support double buffering
PFD_TYPE_RGBA, // support RGBA
16, // bit color mode
0, 0, 0, 0, 0, 0, // ignore color bits
0, // no alpha buffer
0, // ignore shift bit
0, // no accumulation buffer
0, 0, 0, 0, // ignore accumulation bits
16, // number of depth buffer bits
0, // number of stencil buffer bits
0, // 0 means no auxiliary buffer
PFD_MAIN_PLANE, // The main drawing plane
0, // this is reserved
0, 0, 0 }; // layer masks ignored

// 準備一個裝置內容給 OpenGL 視窗, 並試著找到一個圖素格式符合我們上面所描述的
if (!(nPixelFormat = ChoosePixelFormat(hDC, &pfd))) // Did Windows Find A Matching Pixel Format?
{
MessageBoxA(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE; // Return FALSE
}

//設定圖素格式.
if(!SetPixelFormat(hDC, nPixelFormat, &pfd)) // Are We Able To Set The Pixel Format?
{
MessageBoxA(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}

return TRUE;
}



4.設定OpenGL View Port
這個函式在程式一開始執行時, 至少會被執行一次, 以設定透視觀點. 在改變視窗大小時, 也必須呼叫此函式, OpenGL 畫面會依據視窗顯示的寬高來調整大小


GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}

glViewport(0,0,width,height); // Reset The Current Viewport

glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix

// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}



4.設定OpenGL的參數

下面這一段程式碼就是用來設定 OpenGL. 我們設定了清除畫面的顏色, 我們開啟深度緩衝區, 以及平滑著色功能, 等等. 這個函式會在 OpenGL 視窗建立後才被呼叫

int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
return TRUE; // Initialization Went OK
}

5.繪製Model
所有繪圖作業的地方, 都放在此函式當中, 在此, 我們繪製一個矩形

int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix

glTranslatef(0.0, 0.0, -10.0);
glColor3f(60.0, 0.0, 230.0);
glRectf(0.0, 0.0, 1.0, 1.0);

return TRUE; // Keep Going
}

while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
else
{
DrawGLScene();
SwapBuffers(g_hDC);

}
}




6.殺掉 OpenGL 視窗, 並將一切的東西釋放掉

GLvoid KillGLWindow(GLvoid) // Properly Kill The Window
{
if (g_hRC) // Do We Have A Rendering Context?
{
if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
{
MessageBoxA(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}

if (!wglDeleteContext(g_hRC)) // Are We Able To Delete The RC?
{
MessageBoxA(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
g_hRC=NULL; // Set RC To NULL
}

if (g_hDC && !ReleaseDC(g_hWnd,g_hDC)) // Are We Able To Release The DC
{
MessageBoxA(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
g_hDC=NULL; // Set DC To NULL
}

if (g_hWnd && !DestroyWindow(g_hWnd)) // Are We Able To Destroy The Window?
{
MessageBoxA(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
g_hWnd=NULL; // Set hWnd To NULL
}

if (!UnregisterClass("MY_WINDOWS_CLASS", g_hInstance)) // Are We Able To Unregister Class
{
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
g_hInstance=NULL; // Set hInstance To NULL
}
}

下面圖示為此範例的結果:

2009年7月5日 星期日

OpenGL帶來的3D世界

還記得多年前, 原本不愛寫程式的我, 卻在大學專題製作中, 開始接觸到OpenGL API, 透過OpenGL呈現的3D視覺效果, 讓我開始enjoy在coding和3D modeling當中. 而這也影響到, 我之後所選擇工作的內容, 不在是老本行(機械相關產業), 而是軟體業或和3D有關聯的工作.
而什麼是OpenGL(Open Graphics Library)呢? 簡單地說就是"公開的標準繪圖介面", 它定義了一個跨程式語言跨平台的編成介面規格,並可用來產生2D3D圖象.

OpenGL可分成兩種版本, 分別為硬體純軟體實作版本。
硬體實作版本會透過ICD(Installable-Client Driver,它是硬體驅動程式的介面)
來辨別是否可以透過硬體處理(OpenGL應用程式會連結opengl32.dll,當應用程式呼叫OpenGL函式,便會把工作交給ICD處理),如果沒有則透過CPU進行運算。
純軟體的版本是使用SGI所提供的靜態函式庫,所有的運算都是透過CPU來達成.


關於OpenGL的相關網站, 有非常多, 可參考下面列出的網址
:

什麼是OpenGL?
OpenGL 教學文件:
http://janusbooks.myweb.hinet.net/opengl/what_is_opengl.html
OpenGL的維基百科 :
http://zh.wikipedia.org/wiki/OpenGL

OpenGL官網:
OpenGL函式庫 : http://www.opengl.org/sdk/docs/man/
OpenGL函式庫: http://www.xmission.com/~nate/opengl.html

OpenGL教學

OpenGL Reference Manual: http://www.glprogramming.com/blue/
OpenGL Programming Guide: http://orion.lcg.ufrj.br/compgraf1/downloads/OpenGL_Programming_Guide/index.html
OpenGL step by step : http://www.pinxue.net/OpenGL/openglstepbystep.htm
OpenGL tutorial: http://www.songho.ca/opengl/index.html
codesample : http://www.codesampler.com/oglsrc.htm

下面的圖示, 是我利用C搭配OpenGL寫出來的作品:
電腦繪圖學


B-Spline curve


NURBS Surface


校徽



Shadow



3D modeling



Mesh


機構設計

正齒輪模擬



魯式鼓風機


凸輪教學軟體



連桿機構


非圓形齒輪