Showing posts with label Windows. Show all posts
Showing posts with label Windows. Show all posts

2009-03-31

Win32++: 在 Dialog 中使用 ListView

资源文件中有:

IDD_MAIN DIALOG 0, 0, 186, 95
...
{
  ...
  CONTROL         "", IDC_LSTMAIN, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_REPORT, 7, 7, 118, 81, WS_EX_LEFTSCROLLBAR
}
另有 Dialog :
class CMainDialog : public CDialog
{
...
private:
    CListView   m_lsvMain;
};
则,在:
BOOL CMainDialog::OnInitDialog()
{
    // 加上下面这行:
    m_lsvMain.AttachDlgItem(IDC_LSTMAIN, this);
    // 用 AttachDlgItem(UINT nID, CWnd* pParent) 将Dialog的控件附加到CListView对象。
    ...

    // 添加列
    m_lsvMain.InsertColumn(0, _T("Column 0"), LVCFMT_LEFT, 60);
    //m_lsvMain.InsertColumn(1, _T("Column 1"), LVCFMT_LEFT, 60);

    // 添加项
    m_lsvMain.InsertItem(0, _T("Item 0"));
    m_lsvMain.InsertItem(1, _T("Item 1"));
    m_lsvMain.InsertItem(2, _T("Item 2"));
    m_lsvMain.InsertItem(3, _T("Item 3"));

}

注:
另外 641 中的 InsertColumn(int iCol, LPCTSTR pszColumnHeading, int iFormat, int iWidth, int iSubItem)InsertItem(int iItem, LPCTSTR pszText) 是有 BUG 的。
将 listview.h 更新到 SVN 里面最新的 749 后正常。

//EOF Read More...

2009-03-29

Win32++ CodeBlocks templates & wizard

Win32++ is a C++ library used to build windows GUI applications.
http://sourceforge.net/projects/win32-framework/
Win32 平台上的一个轻量级的 C++ GUI开发库,可以用在 GCC 编译器中。
document:
http://users.bigpond.net.au/programming/documentation.htm

自己花了点时间做了个简陋的 CodeBlocks 的新建 Win32++ 工程的模板向导。

下载:
http://dl.getdropbox.com/u/163800/libs/cxx/Win32%2B%2B/codeblocks_templ.zip

安装步骤:
1. 解包后将 wizard 下的 win32xx 目录放到 [CodeBlocks]\share\CodeBlocks\templates\wizard\ 去。
(其中 [CodeBlocks] 表示 CodeBlocks 的安装目录)
当然也可以放到用户目录中——具体参照 CodeBlocks 的 Wiki。

2. 在 [CodeBlocks]\share\CodeBlocks\templates\wizard\ 中找到 config.script 文件,用文本编辑器打开,在 function RegisterWizards() { ... } 里面加一行:

RegisterWizard(wizProject, _T("win32xx"), _T("Win32++ Application"), _T("GUI"));

3. 这样新建工程的 GUI 分类里面就有 "Win32++ GUI Application" 的选项了,按向导一步步走就可以了。
(当然,前提是你要将 Win32++ 的库引入哦!——在“编译器选项”->"Search directories"->"Compiler"里面加入)

//EOF Read More...

2009-01-21

在程序中处理设备的热插拔通知

注册 WM_DEVICECHANGE 事件,但还不够。
仅注册该事件则仅仅只会收到 DBT_DEVNODES_CHANGED 通知(包括光驱的弹出、收入,网络的通断等都会触发该事件)。
所以还需要用 RegisterDeviceNotification() 注册相应的设备通知。

HDEVNOTIFY RegisterDeviceNotification(
  IN HANDLE hRecipient,  // 注册 WM_DEVICECHANGE 事件的窗口或Service句柄
  IN LPVOID NotificationFilter, // DEV_BROADCAST_DEVICEINTERFACE 结构
  IN DWORD Flags
);

BOOL UnregisterDeviceNotification(
  IN HDEVNOTIFY Handle  // RegisterDeviceNotification() 返回的那个Handle
);
在 DEV_BROADCAST_DEVICEINTERFACE 结构里有个 dbcc_classguid 为需要监听的设备 GUID。
MSDN 上说 RegisterDeviceNotification() 的 Flags 加上 DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 后可以不要GUID 但我这里似乎 不能不要GUID~~ RegisterDeviceNotification() 时失败说 “Bad Data!”~ 不知道是怎么回事,也许没用对吧。

参考:
http://www.microsoft.com/whdc/Driver/tips/PnPUmNotif.mspx
http://msdn.microsoft.com/en-us/library/aa363211(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa363431(VS.85).aspx


另外,在 Linux 上的热插拔通知 可用 udev, HAL, D-BUS。

//EOF Read More...

使用 RegEnumValue 要注意的地方

LONG RegEnumValue(
  HKEY hKey,              // handle to key to query
  DWORD dwIndex,          // index of value to query
  LPTSTR lpValueName,     // address of buffer for value string
  LPDWORD lpcbValueName,  // address for size of value buffer
  LPDWORD lpReserved,     // reserved
  LPDWORD lpType,         // address of buffer for type code
  LPBYTE lpData,          // address of buffer for value data
  LPDWORD lpcbData        // address for size of data buffer
);

返回值 ERROR_NO_MORE_ITEMS,表示都枚舉完了。
dwIndex 為索引,如果是枚舉并刪除的話,就一直為0就行了。
lpcbValueName 這個是ValueNameBuffer 的大小,這個地方要注意!!每次調用前設置成buffer大小,調用后都會設置成返回的ValueName實際的長度,所以這里需要在每次調用前都設置一下,@@ 暈死~,沒注意看MSDN。
lpcbData 同上。

//EOF Read More...

2009-01-11

修改文件/資料夾的用戶訪問權限

用WinAPI:

BOOL SetFileSecurity(
  LPCTSTR lpFileName,  // address of string for filename
  SECURITY_INFORMATION SecurityInformation,
                       // type of information to set
  PSECURITY_DESCRIPTOR pSecurityDescriptor 
                       // address of security descriptor
);
如:
::SetFileSecurity(szFileName, DACL_SECURITY_INFORMATION, psd);
其中 psd 的取得見上一篇:http://dave3068.blogspot.com/2009/01/securityattributeslpsecuritydescriptor.html

另外,對上一篇的補充:
SECURITY_ATTRIBUTES 中 lpSecurityDescriptor 的使用還可以使用 API :
SetSecurityDescriptorDacl
SetSecurityDescriptorControl
等。
不過感覺一般情況下還是這個 ConvertStringSecurityDescriptorToSecurityDescriptor 方便些 :)。
要如何使用就要看具體的場合了。

//EOF Read More...

2009-01-10

SECURITY_ATTRIBUTES.lpSecurityDescriptor 的使用

在 WinAPI:CreateFile 等函數中有個 SECURITY_ATTRIBUTES 可以用來控制文件的用戶訪問權限,但一直不知道SECURITY_ATTRIBUTES結構中的lpSecurityDescriptor如何設置,今天查了一下MSDN發現可以用函數:

BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptor(
  __in   LPCTSTR StringSecurityDescriptor,
  __in   DWORD StringSDRevision,
  __out  PSECURITY_DESCRIPTOR *SecurityDescriptor,
  __out  PULONG SecurityDescriptorSize
);
來設置pSa->lpSecurityDescriptor。
要使用該函數需要引入Sddl.h 頭文件,但 VC6 里面沒有這個頭文件。
還有個方法是自己 LoadLibrary => GetProcAddress 來取得:
ConvertStringSecurityDescriptorToSecurityDescriptor 在 Windows 2000 Professional 以上的 Advapi32.dll 中。
可以用以下代碼得到:
typedef BOOL (WINAPI *FN__CSSDTSD__) (
  IN LPCTSTR,
  IN DWORD,
  OUT PSECURITY_DESCRIPTOR *,
  OUT PULONG);

FN__CSSDTSD__ ConvertStringSecurityDescriptorToSecurityDescriptor = NULL;

//   SDDL   Version   information
#define SDDL_REVISION_1  1
#define SDDL_REVISION  SDDL_REVISION_1


void _initLIBS()
{
 HMODULE hAdvapi32 = ::LoadLibrary("Advapi32");
 if (hAdvapi32)
 {
  ConvertStringSecurityDescriptorToSecurityDescriptor =
   (FN__CSSDTSD__)::GetProcAddress(
    hAdvapi32,
    "ConvertStringSecurityDescriptorToSecurityDescriptorA");
 }
}

參考:
http://msdn.microsoft.com/en-us/library/ms717798.aspx
http://msdn.microsoft.com/en-us/library/aa379570%28VS.85%29.aspx
http://msdn.microsoft.com/en-us/library/aa376401%28VS.85%29.aspx

//EOF Read More...

2008-12-31

替換Windows的Desktop時,如何獲取應用程序注冊的圖標?

今天整理硬盤的時候發現這個,放上來算了,希望對需要的人有幫助。
是以前寫的一個東西——曾經覺得 Windows 的 Desktop 太難看了,所以打算自己寫一個。其它的沒啥子主要是些 GDI+ 的操作。
中間遇到的最大問題是如何獲得應用程序對 TrayNotifyIcon 的注冊。關于這個問題曾經 debug 了 explorer.exe ,才得出以下方法:(Windows XP)

1、如何接收應用程序的注冊圖標通知:
自己實現一個Window注冊Class為"Shell_TrayWnd"(Windows界面中的控件元素都可看作Window——所以叫做 Windows 嘛~~),其下一個子窗口(控件)注冊Class為"TrayNotifyWnd"。
在注冊Class為"Shell_TrayWnd"的窗口中可處理 WM_COPYDATA 消息:
此時 lParam 為 PCOPYDATASTRUCT pcds
(pcds->dwData == 1) 時表示是一個通知消息
此時的 pcds->lpData 結構如下:
(這是我自己定義的一個結構,不知道MSDN是否有這樣的結構,反正我是沒找到,所以自定義了個)

// the struct for WM_COPYDATA to "Shell_TrayWnd"
typedef struct _NOTIFY_MSG_DATA {
 DWORD dwUnknow;  // ??? I don't know what's this ?
 DWORD dwNotifyCode; // NIM_ADD, NIM_DELETE, NIM_MODIFY, ...
 NOTIFYICONDATA nid; // 這里就是應用程序注冊圖標時的數據了
 bool operator== (const _NOTIFY_MSG_DATA& nmd) const
 {
  return nid.hWnd == nmd.nid.hWnd;
 };
} NOTIFY_MSG_DATA, *PNOTIFY_MSG_DATA;
子窗口注冊Class為"TrayNotifyWnd"主要是想和 explorer.exe 保持一致罷了,接收消息的實質上是"Shell_TrayWnd"。

另外,要注意的是:
if (pnid->uFlags & NIF_ICON) // pnid為上面的NOTIFYICONDATA的指針
{
 // Some applications destroy the icon immediately after completing the
 // NIM_ADD/MODIFY message, so we have to make a copy of it.
 if (hIcon)
  ::DestroyIcon(hIcon);
 hIcon = (HICON) ::CopyIcon(pnid->hIcon);

 bChanged = true;
}
某些程序在注冊圖標后會 destory 這個 hIcon ,所以最好是自己拷貝一份——要不然也會出現某些得到的圖標莫名其妙不見了的情況。

2、explorer.exe 出異常中途結束后重啟,得到被終結之前的圖標。
(在XP之前的Win版本中是會丟失的——失去之前注冊的程序圖標)
XP 中主要在以下注冊表項目中,以二進制方式存儲:
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify]
IconStreams 当前项目
PastIconsStream 过去的项目
存儲的數據格式如何,自己dump一下就知道了 :)


嗯……其它的就沒有什么好多說的了,基本上就是一些 GDI+ 操作了。

哦!還有就是 explorer.exe 除了桌面外,還充當文件管理器等其它的作用,所以要替換它的話除了繪制桌面還要做其它方面的準備,或者那些方面的替代品。

差不多就是這些了,以上!

//EOF Read More...

2007-10-28

VC notes[01]

许久没用Win了,生疏了很多。记些笔记:

  1. 让Dialog中能接收 WM_CHAR,及按键时不要“咚咚”声

  2. 在 Dialog::PreTranslateMessage(MSG* pMsg) 中让Dialog跳过WM_CHAR的处理(return FALSE):
    if (pMsg->message == WM_KEYDOWN 
          || pMsg->message == WM_KEYUP 
          || pMsg->message == WM_CHAR)
        return FALSE; // 解决按键时的“咚咚”声,及让Dialog中能接收 WM_CHAR
    //(Dialog 的回车自动 OK,ESC 自动 CANCEL 也可以用这种方式解决)

  3. 在某窗体中禁用输入法:(标准 Windowz GUI 中控件也是窗体)
    处理 WM_INPUTLANGCHANGEREQUEST 并 return 0;
  4. 自绘输入光标
    WM_SETFOCUS:
    // 注:这里我开始用this->CreateCaret(NULL),发现只有个小黑点,所以用可以定义大小的。
    ::CreateCaret(this->m_hWnd, NULL, 2, 25);//(HBITMAP)1是灰块,NULL是黑块,也可以定制BMP
    ::SetCaretPos(50,15);    // 设置光标位置
    this->ShowCaret();
     
    WM_KILLFOCUS:
     
    this->HideCaret();
    ::DestroyCaret();
  5. 动态设置光标位置
    结合如下API:(注意:DC的字体)
    SIZE    size;    // 字串高度、宽度
    GetTextExtentexPoint32(hdc, str, strlen, &size);
  6. 限制窗口显示的大小
    (注:该消息为Win发送处理,用户只需设置其值就行了,只设置需要的其它的交给系统调整)
    WM_GETMINMAXINFO: 
     
    // 窗口最小能调整到的大小
    lpMinMaxInfo->ptMinTrackSize.x = 640;
    lpMinMaxInfo->ptMinTrackSize.y = 480;
    // 窗口最大能调整到的大小
    lpMinMaxInfo->ptMaxTrackSize.x = 800;
    lpMinMaxInfo->ptMaxTrackSize.y = 600;
    // 最大化窗口时的大小
    lpMinMaxInfo->ptMaxSize.x = 800;
    lpMinMaxInfo->ptMaxSize.y = 600;
    // 最大化窗口时的位置
    lpMinMaxInfo->ptMaxPosition.x = 50;
    lpMinMaxInfo->ptMaxPosition.y = 60;
     
    return 0; // 自己处理后要 return 0;


//EOF Read More...