Windows 7 taskbar and startmenu pin

简介: 原文 Windows 7 taskbar and startmenu pin 在Windows 7上,用户可以将自己喜欢的软件“钉”在开始菜单或任务栏,使用起来更加方便。但有时候我们也需要用程序来将这个过程自动化,比如在IT环境里定制客户机,或者我们从一台Win7系统迁移到另一台Win7系统时。

原文 Windows 7 taskbar and startmenu pin

在Windows 7上,用户可以将自己喜欢的软件“钉”在开始菜单或任务栏,使用起来更加方便。但有时候我们也需要用程序来将这个过程自动化,比如在IT环境里定制客户机,或者我们从一台Win7系统迁移到另一台Win7系统时。

怎么知道已有哪些软件被“钉”在开始菜单或任务栏:

当软件“钉”在开始菜单或任务栏后,系统会在"%appdata%\microsoft\internet explorer\Quick Launch\User Pinned"下的"StartMenu"和"TaskBar"目录内创建软件的链接。我们只要看这两个目录下分别有哪些有效链接就可以知道开始菜单和任务栏分别钉有哪些软件。对于每一个链接,我们可以知道它链接了那个程序,然后在目标系统上,我们就可以将这个程序钉在开始菜单或任务栏上(目标系统上也要有这个程序)。

如何把软件“钉”在开始菜单或任务栏:

需要注意的是只能将链接钉在开始菜单或任务栏,而且链接必须指向可执行程序,所以我们需要先为目标程序创建一个链接,然后调用ShellExecute,将链接钉住,钉完后这个链接可以删掉。任务栏上钉与解除时传递给ShellExecute的lpOperation参数是taskbarpin/taskbarunpin,而开始菜单的lpOperation参数是startpin/startunpin。

示例,将IE钉在任务栏上:

1. 在桌面上为IE创建链接IE.lnk

2. ShellExecute(NULL, "taskbarpin", "c:\users\username\Desktop\IE.lnk", NULL, NULL, 0)

以上有一个限制,就是不知道在任务栏上链接的顺序。

 

Windows XP 任务栏的遍历

2009-05-04 9:26

    这里的方法可以找到XP下的任务栏,并对任务栏进行遍历,在其他系统上就需要相应的改动了。这里是先找到ToolbarWindow32这个窗口,然后再用通用的遍历Toolbar的方法查找各个按钮;这里有一点特别的是,要用到跨进程缓冲区(因为任务栏和遍历程序不是在同一个进程)。 
    在XP下有一个“分组相似任务栏按钮”特性,如果有一个新的进程窗口要在任务栏上显示,则系统会创建两个按钮,一个按钮有BTNS_DROPDOWN style,默认隐藏,在任务分组后显示(这个style指定它显示一个箭头图标);另一个按钮就是通常我们看到的任务栏按钮。 
    struct TBBUTTONDATA是从网上找到的,没有在微软的文档中发现,但在XP上验证是有效的。 
    在遍历按钮,SendMessage的时候,要注意是Zero-based index 还是 Command ID,现在一些网上的资料范例在需要传Command ID的时候传Zero-based index做参数,这是错误的。 
HWND GetTaskButtonHost(HWND hShellTrayWnd) 

    HWND hWnd = FindWindowEx(hShellTrayWnd, NULL, _T("ReBarWindow32"), NULL); 
    if (hWnd == NULL) 
        return FALSE; 
    hWnd = FindWindowEx(hWnd, NULL, _T("MSTaskSwWClass"), NULL); 
    if (hWnd == NULL) 
        return FALSE; 
    hWnd = FindWindowEx(hWnd, NULL, _T("ToolbarWindow32"), NULL); 
    return hWnd; 

//MSDN: To continue enumeration, the callback function must return TRUE; to stop enumeration, it must return FALSE. 
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) 

    TCHAR strClsName[MAX_PATH+1] = _T(""); 
    GetClassName(hwnd, strClsName, MAX_PATH+1); 
    if (_tcsicmp(strClsName, _T("Shell_TrayWnd")) == 0) 
    { 
        HWND hShellTrayWnd = GetTaskButtonHost(hwnd); 
        if (hShellTrayWnd) 
        { 
            HWND *pHwnd = (HWND *)lParam; 
            *pHwnd = hShellTrayWnd; 
            return FALSE; 
        } 
    } 
    return TRUE; 

struct TBBUTTONDATA 

    HWND hwnd; //the handle of the window on the taskbar 
    UINT uID; 
    UINT uCallbackMessage; 
    DWORD Reserved[2]; 
    HICON hIcon; 
}; 
//This solution works on XP. 
void EnumTasks() 

    HWND hWnd = NULL; 
    EnumWindows(EnumWindowsProc, (LPARAM)&hWnd); 
    if (hWnd == NULL) 
        return; 
    DWORD dwProcID = 0; 
    GetWindowThreadProcessId(hWnd, &dwProcID); 
    HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, dwProcID); 
    if (hProcess == NULL) 
        return; 
    LPTSTR pProcBuf = NULL; //pointer to the buffer allocated in another process 
    TBBUTTON tbb; 
    TBBUTTONDATA tbbData; 
    TCHAR strCaption[MAX_PATH+1] = _T(""); 
    pProcBuf = (LPTSTR)VirtualAllocEx(hProcess, NULL, sizeof(strCaption), MEM_COMMIT, PAGE_READWRITE); 
    if (pProcBuf == NULL) 
    { 
        CloseHandle(hProcess); 
        return; 
    } 
    DWORD nTaskCount = ::SendMessage(hWnd, TB_BUTTONCOUNT, 0, 0); 
    for (DWORD i = 0; i < nTaskCount; i++) 
    { 
        ZeroMemory(&tbb, sizeof(TBBUTTON)); 
        WriteProcessMemory(hProcess, pProcBuf, &tbb, sizeof(TBBUTTON), NULL); 
        SendMessage(hWnd, TB_GETBUTTON, i/*Zero-based index*/, (LPARAM)pProcBuf); 
        ReadProcessMemory(hProcess, pProcBuf, &tbb, sizeof(TBBUTTON), NULL); 
        //Group similar task-bar buttons(a feature of Windows): if the top-level window is 
        //shown on task-bar, Windows will create another dropdown button for each process. 
        if (tbb.fsStyle & BTNS_DROPDOWN) 
            continue; 
        ReadProcessMemory(hProcess, (LPCVOID)tbb.dwData, &tbbData, sizeof(TBBUTTONDATA), NULL); 
        DWORD nDesireLen = SendMessage(hWnd, TB_GETBUTTONTEXT, tbb.idCommand, 0); //length not including null terminator 
        if (nDesireLen >= sizeof(strCaption)) 
            continue; 
        ZeroMemory(strCaption, sizeof(strCaption)); 
        WriteProcessMemory(hProcess, pProcBuf, strCaption, sizeof(strCaption), NULL); 
        SendMessage(hWnd, TB_GETBUTTONTEXT, tbb.idCommand, (LPARAM)pProcBuf); 
        ReadProcessMemory(hProcess, pProcBuf, strCaption, sizeof(strCaption), NULL); 
        OutputDebugInfo(L"%s\n", strCaption); 
    } 
    VirtualFreeEx(hProcess, pProcBuf, 0, MEM_RELEASE); 
    CloseHandle(hProcess); 
}

 

前一篇Windows XP 任务栏的遍历介绍了在XP下遍历任务栏的方法,可以精确遍历出任务栏的按钮;这篇博客介绍一种通用的遍历任务栏的方法(不仅限于XP),但可能结果不是太精确。 
对于什么样的窗口才会在任务栏上创建按钮,MSDN上的说法是:

The Shell creates a button on the taskbar whenever an application creates a window that isn't owned. To ensure that the window button is placed on the taskbar, create an unowned window with the WS_EX_APPWINDOW extended style. To prevent the window button from being placed on the taskbar, create the unowned window with the WS_EX_TOOLWINDOW extended style. As an alternative, you can create a hidden window and make this hidden window the owner of your visible window.

做了一些测试,总结的结果是:

1、如果窗口没有被其他窗口拥有(GetWindow(hwnd, GW_OWNER) == 0),那么默认情况下它会在任务栏中创建按钮,除非:

a). 窗口被隐藏了

或者:

b). 窗口有WS_EX_TOOLWINDOW风格,且没有WS_EX_APPWINDOW风格

2、如果窗口被其他窗口拥有,默认不会在任务栏创建按钮,除非:

a). 窗口可见,且有WS_EX_APPWINDOW风格

从1、2点可以得出结论,如果窗口可见,有WS_EX_APPWINDOW和WS_EX_TOOLWINDOW风格,那么,这个窗口是一个Tool window,且在任务栏上有按钮。

范例:

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) 

    LONG lExStyle = ::GetWindowLong(hwnd, GWL_EXSTYLE); 
    if (::IsWindowVisible(hwnd) && 
        ( (lExStyle & WS_EX_APPWINDOW) || 
          (GetWindow(hwnd, GW_OWNER) == NULL && (lExStyle & WS_EX_TOOLWINDOW) == 0) ) 
        ) 
    { 
        TCHAR strTitle[MAX_PATH+1] = _T(""); 
        GetWindowText(hwnd, strTitle, MAX_PATH+1); 
        OutputDebugInfo(L"%s\n", strTitle); 
    } 
    return TRUE; 

EnumWindows(EnumWindowsProc, NULL);

 

 

 

 

Vista UAC : 以管理员权限运行程序

2009-04-25 20:21

在Windows Vista启用UAC后,程序启动后默认没有管理员权限,

即使当前的用户属于管理员组。如果要使程序获得管理员权限,还需要一些额外的工作。可以从两个角度来看待: 
一、从程序用户的角度: 
1、用鼠标右击某个应用程序(例如cmd.exe), 再选择"Run As Administrator"(在旧版本里是"Run Elevated")来以管理员权限运行它 
2、在程序(或其快捷方式)的属性Compatibility中选择Run this program as an administrator来运行 
3、在程序的安装目录,添加一个Manifest文件,使程序以管理员权限运行 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestversion="1.0"> 
<trustinfo xmlns="urn:schemas-microsoft-com:asm.v3"> 
<security> 
<requestedprivileges> 
<requestedexecutionlevel level="requireAdministrator" uiaccess="false"> 
</requestedexecutionlevel> 
</requestedprivileges> 
</security> 
</trustinfo> 
4、有编程经验的用户也可以写脚本来运行程序,如: 
objShell = new ActiveXObject("Shell.Application"); 
objShell.ShellExecute(app, args, "", "runas"); 
C#示例: 
ProcessStartInfo startInfo = new ProcessStartInfo(); 
startInfo.FileName = "cmd.exe"; 
startInfo.Arguments = "/c c:\\test\\script.cmd"; 
startInfo.UseShellExecute = true; 
startInfo.Verb = "RunAs"; 
Process process = new Process(); 
process.StartInfo = startInfo; 
process.Start();

C/C++, 可调用ShellExecute或ShellExecuteEx, 把lpOperation/lpVerb设成"RunAs"就可以

二、从开发人员角度: 
1、在应用程序RC中加入MANIFEST类型资源. 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestversion="1.0"> 
<trustinfo xmlns="urn:schemas-microsoft-com:asm.v3"> 
<security> 
<requestedprivileges> 
<requestedexecutionlevel level="requireAdministrator" uiaccess="false"> 
</requestedexecutionlevel> 
</requestedprivileges> 
</security> 
</trustinfo> 
2、以上几种方法都使得程序刚运行就要求管理员权限,要在程序运行中动态要求管理员权限则可以使用COM Elevation Moniker。可参考:http://msdn2.microsoft.com/en-us/library/ms679687.aspx

目录
相关文章
|
1月前
|
Linux Windows
Windows Server 下文件同步
Windows Server 下文件同步
34 0
|
14天前
|
编解码 安全 网络安全
RealVNC的 VNC server在windows7系统下无法正确运行
在Windows 7上运行旧版VNC Server(如4.1.2)可能存在兼容性问题,但可通过调整配置解决。步骤包括:安装VNC Server,设置兼容性模式(选择Windows XP SP3),启动VNC Server,配置VNC连接参数。若遇到问题,检查防火墙设置,确保系统更新,并考虑升级到新版VNC Server以提高性能和兼容性。
|
27天前
|
开发框架 .NET API
在Windows Server 2008 R2上运行.Net 8应用
在Windows Server 2008 R2上成功运行.Net 8程序,需安装三个补丁:Windows Server 2008 R2 SP1 (KB976932)是基础更新;VC_redist.x64提供MSVC库支持;KB3063858解决.NET运行时加载`kernel.dll`的路径问题。KB3063858可能需要KB2533623。详细信息和下载链接在文中给出。
|
1月前
|
网络协议 Unix Linux
【技术分享】Server / Server Software / Unix Windows OS
Server / Server Software / Unix Windows OS
54 2
|
1月前
|
开发框架 .NET 数据库
修改windows server 2008 时间和日期格式
修改windows server 2008 时间和日期格式
18 1
|
1月前
|
开发框架 JavaScript 安全
WIndows Server 2016 部署 Web服务(简单篇)
WIndows Server 2016 部署 Web服务(简单篇)
|
1月前
|
安全 测试技术 网络安全
WIndows Server 2016 部署 PKI + 证书
WIndows Server 2016 部署 PKI + 证书
|
1月前
|
安全 关系型数据库 虚拟化
WIndows Server 远程桌面服务—RDS
WIndows Server 远程桌面服务—RDS