Sean's Note: Windows Programming
顯示具有 Windows Programming 標籤的文章。 顯示所有文章
顯示具有 Windows Programming 標籤的文章。 顯示所有文章

2016年3月14日 星期一

SetEnvironmentVariable VS getenv

最近發現一個奇怪的現象,
就是在 VS 的 cpp 裡呼叫 SetEnvironmentVariable 設定環境變數,
但從 Python code 裡印出 os.osenviron 卻看不到所設定的變數,
一查才發現,Python 裡的 os.osenviron 是用 getenv實作的。
GetEnvironmentVariable/SetEnvironmentVariable 是 Windows API,
而 setenv/getenv 是 CRT 函式。CRT 在開始的時候便會透過 Windows API GetEnvironmentStrings 將回傳值存入自己的資料結構之下(EX: MSVCR80!environ),
而此後 getenv 便是對這份副本做操作。

結論就是不要混用 SetEnvironmentVariable 和 getenv 啊!!

Ref:
  1. https://bugs.python.org/issue16633
  2. http://blogs.msmvps.com/senthil/2009/10/13/when-what-you-set-is-not-what-you-get-setenvironmentvariable-and-getenv/

2015年8月18日 星期二

Writing DPI-Aware Desktop and Win32 Applications

在 Windows 上,依據 DPI 的設定可將應用程式分為三類:

Not DPI-aware Applications

沒有設定 DPI-aware 的應用程式,皆以 96 DPI 做 rendering。
系統的 Desktop Window Manager (DWM) 會自動縮放 (virtualizes and scales) 這些應用程式。


System-DPI Aware Application

從 Windows Vista 開始到 Windows 8,應用程式可以依據系統 DPI 的設定,自己去做最佳化,而不是透過 DWM 來做。但如果是在不同 DPI 的螢幕間移動,DWM 還是會自動縮放。 


Per Monitor-DPI Aware Applications

從 Windows 8.1 開始,多了這個類別。當使用者改變了 DPI 設定或在不同 DPI 的螢幕間移動時,這些應用程式將會動態縮放。DWM 同樣不會去自動縮放這些應用程式。

DPI Virtualization and Scaling 

從 Window Vista 開始,引進了新功能  DPI virtualization,這項功能會將沒有設定 DPI-aware 的應用程式,自動縮放其文字和其他 UI 元件。這樣應用程式的字在 high DPI 的螢幕上就不會看起來特別的小。而從 Window 8.1 開始,延展了 DPI virtualization 的功能,DPI 從系統層級變成螢幕層級。


Supporting Dynamic DPI Changes

那應用程式該做哪些事情來支援 DPI 的動態設定呢?
  1. Set the DPI Awareness Level
    可以透過 manifest 檔或 SetProcessDpiAwareness API 來做設定。
  2. Get the DPI for the current monitor
    呼叫 GetDPIForMonitor API 來取得值。
  3. Listen for DPI changes
    聆聽 WM_DPICHANGED 這個 windows message。
  4. Respond to DPI changes
    收到上述訊息後,改變視窗大小或縮放 UI 元件等等。

Ref : Writing DPI-Aware Desktop and Win32 Applications

2013年10月18日 星期五

Windows Messsage: Clicking mouse button will also trigger mouse down event.

用 Microsoft Spy++ 攔了一下滑鼠相關的 messages,

發現原來只按滑鼠左鍵一樣也會觸發 WM_MOUSEMOVE 。

WM_SETCURSOR
WM_SETCURSOR
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_SETCURSOR
WM_SETCURSOR
WM_MOUSEMOVE

2013年10月3日 星期四

Symbols and Symbol Files

當程式做完連結 (link) 後,連結器 (Linker) 除了產生 .exe 和 .dll 檔之外,也會額外產生

symbol 檔。symbol 檔包含了執行程式時所不需要的資料,但在除錯上就極為有用:

  • 全域變數
  • 區域變數
  • 函式的名稱還有進入點的位址
  • Frame pointer omission (FPO) 的紀錄
  • 原始碼的行號

這些每一個項目都稱為 symbol,所以一個 symbol 檔會包含有很多 symbols,

symbol 檔的副檔名為 .pdb 或 .dbg,Visual C++ 6.0 Linker 之後只會產生 .pdb。


Ref: http://msdn.microsoft.com/en-us/library/windows/hardware/ff558825(v=vs.85).aspx

2013年9月30日 星期一

Symbol path for Windows debuggers

一般指定本地端的 symbol 檔路徑的指令如下,
.sympath c:\MySymbols
而 Debugger 查詢 symbol 檔的順序為:
  1. c:\MySymbols\symbols\dll
  2. c:\MySymbols\dll
  3. c:\MySymbols
  4. Current Directory
  5. Current Directory\dll

如果電腦有連接網路最有效率的方法就是直接連 Symbol Server,

srv*symbolstore

Microsoft's symbol store:

.sympath srv*http://msdl.microsoft.com/download/symbols

建議加上 Cahce:

.sympath cache*;srv*http://msdl.microsoft.com/download/symbols

cache* 是指把 symbol 檔存到 default 的本地端,下次就不用載一次。

2013年5月13日 星期一

Be cautious with strncpy_s

strncpy_s 的宣告如下:


注意 numberOfElements 一定要大於 count,

Ex:

char dst[6]; 

strncpy_s(dst, 6, "a long string", 5);

dst 必須保留一位置給結束字元(null terminator)。 

否則有機會 crash。

2013年3月5日 星期二

把常用的 TortoiseSVN 功能整合進 Visual Studio

我們可以將 TortoiseSVN 常用的功能,如 Log 和 Blame 整合進 Visual Studio,

步驟如下:

開啟 VS -> Tools -> External Tools...

[External Tools]






















Command: C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe

Arguments(Log): /command:log /path:"$(ItemPath)"

Arguments(Blame): /command:blame /path:"$(ItemPath)" /line:$(CurLine)

如此一來,就可以在 VS 上對某一段 code 做 Log 和 Blame 啦! 相當好用!

2013年3月4日 星期一

利用指令透過 Visual Studio 開啟指定檔案


我們可以在執行檔 C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/devenv.exe

後面加上:

A.cpp /command "Edit.Goto 200"

或是

/edit A.cpp

兩者的差異是,前者會開啟新的 VS 並可指定行號,後者會用已開啟的 VS 做為編輯器,

但無法指定行號。

2013年1月7日 星期一

Visual Studio 專案設定檔的存放路徑

C:\Users\[UserName]\AppData\Local\Microsoft\VisualStudio\8.0\VCComponents.dat

裡面存放著 Include Dirs, Lib Dirs 等等的路徑,我們常常對於不同的專案會有

不同的設定,此時只要備份並覆蓋該檔即可。

2012年10月31日 星期三

利用 WM_GESTURE 寫出有 Touch 功能的程式

如果只想做出簡單的 PAN 功能,可透過接收 WM_TABLET_FLICK 訊息來達成,

其提供了八個方向,但在 Win8 上好像收不到這個訊息。

另外的替代方案是,在 Win7 以上的作業系統,我們可以透過接受 WM_GESTURE 來實作。

在使用前先透過 WM_GESTURENOTIFY 和 SetGestureConfig() 設定我們要或不要接收

哪些手勢。假如設定好只接受 PAN 的手勢後,即可在 WM_GESTURE 用 GetGestureInfo()

攔到 GESTUREINFO.dwID = GID_PAN 的資訊。

另外由 GESTUREINFO.dwFlags = GF_BEGIN/GF_INERTIA/GF_END 來分析起始點、慣性點和

終點。要注意的是,除非有明確的 PAN 動作(手指離開時的點需停留得夠久),否則

GF_BEGIN/GF_END 並不會成對出現,而會出現 GF_INERTIA 的慣性點。

GF_INERTIA 是用來實作像是拖曳卷軸時手已經放開的滑動效果。

2012年10月24日 星期三

改變 TextOut 時的字型或大小

我們可以利用 CreateFont() 和 CreateFontIndirect() 來產生 HFONT 物件。

hFont = 

CreateFont(48,0,0,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_OUTLIN 

E_PRECIS, CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, 

VARIABLE_PITCH,TEXT("Impact")); 

然後再將此字型物件置換到 DC 上即可。

SelectObject(hDC, hFont);

TextOut(hDC, 0, 0, "Hello", lstrlen("Hello"));

Ref: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183499(v=vs.85).aspx

畫出只有邊框的透明 Rectangle

我們只要在選擇筆刷時設 NULL_BRUSH 即可 :

SelectObject(hDC,GetStockObject(NULL_BRUSH));

Rectangle(hDC, 0, 0, 100, 100);

2012年8月22日 星期三

程式相容性助理

在 Win7 或 Win8 上常常可以看到一些程式直行或關閉時,跳出程式相容性助理
(Program Compatibility Assistant) 的視窗,跳出的原因有很多種可以參考這篇,
http://msdn.microsoft.com/library/bb756937.aspx。若想透過程式的方法強制把 PCA 關掉,
可以在開發程式時的 Manifest 檔加上一些屬性,詳細可參考:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd371711(v=vs.85).aspx 。

2012年8月13日 星期一

[Win8] 以檔案開啟...

在 Win8 裡第一次執行文件或檔案時,會跳出你要用哪種檔案來開啟的小視窗,此時該檔案右

側的文字所顯示的即是檔案的描述(File Description)。在用 Visual Studio 開發 Windows App 時,

可從 Resource View 裡,找到專案的 Version\VS_VERSION_INFO 資源檔去做更改。

同時,這個值會被 cache 在 :


Path: HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\Shell\MuiCache

Name: C:\Windows\system32\mspaint.exe.FriendlyAppName

Data: Paint






2012年6月20日 星期三

[MFC] 將使用者設定儲存到 Key 裡

通常一個較好的使用者介面,會在程式關閉時,將使用者的狀態紀錄到系統裡,

等下次使用者開啟軟體時,再將狀態讀出,顯示使用者關閉前的狀態,

而我們可以透過幾個 Windows API 做到這樣的功能。

CWinApp::GetProfileInt
CWinApp::GetProfileString
CWinApp::WriteProfileInt
CWinApp::WriteProfileString

原本這些 API 會將狀態寫到 C:\Windows\XXX.INI 裡,也從這裡讀,

但在 MSDN 上已說這不是個好的方式,建議存放到 Registry Key 裡。


透過 SetRegistryKey(LPCTSTR lpszRegistryKey) 可以指定存放到 Registry Key 而非 INI 檔。


存放的路徑如下:
HKEY_CURRENT_USER\Software\<company name>\<application name>\<section name>\<value name>.


其實 SetRegistryKey 就是把 CWinAp::m_pszProfileName 成員變數設成你所設定的值,

否則預設是 XXX.INI。


注意: 如果是用 Win32 API 的 WriteProfileString 寫到的則是 C:\Windows\win.ini 裡。



2012年6月5日 星期二

把視窗移到最前面

試過了 BringToTop() 和 SetWindowsPos() 都沒什麼用。

SwitchToThisWindow() 有用,但不是想要的效果。

SetForegroundWindow() 有用,但不是每次都成功,

失敗時程式就會在工作列上閃阿閃的 (註 1)。

最後參考了這篇的第二段 code ,終於實現了需要的功能:
http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo

最主要是 AttachThreadInput() 讓 SetForegroundWindow() 幾乎都能成功。


註 1: 利用 SPI_SETFOREGROUNDFLASHCOUNT 可以控制要閃的次數。
SystemParametersInfo( SPI_SETFOREGROUNDFLASHCOUNT, 0, 5, SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);

2012年2月17日 星期五

讀寫 ini 檔

詳見 MSDN。

WritePrivateProfileString(szSection, szTag, szValue, szPath);
GetPrivateProfileString(szSection, szTag, NULL, szValue, MAX_PATH, szPath);

2012年1月19日 星期四

[DEBUG] ProcessMonitor 2.96

ProcessMonitor 可以幫助開發者查看特定應用程式正在執行時,所存取

的 RegKey 和檔案等等,是個相當方便的工具。

下面的網誌作者做了簡略的介紹:
http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/08/18/977.aspx

2012年1月10日 星期二

[Win32] 自訂 Button 的顏色

在 Win32 的視窗程式設計下,想要自訂 Button 的顏色或 Button 文字的顏色,

並非易事,必須搭配 WM_DRAWITEM 來繪製自訂 Button。

1. 首先,在 Button 的 Properties Page 上將 Owner Draw 屬性設成 True。

2. 接收到 WM_DRAWITEM 訊息時繪製 Button 的樣式和欲顯示的字串。

    2.1 利用 DrawEdge() 可繪製 Button 被按下和沒按的樣子。

    2.2 DrawText() 可畫出文字,避免使用 SetWindowText(), 因為其會再觸發

          WM_DRAWITEM  很容易造成無窮回圈,而導致 Stack overflow。