原文 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

Windows 7 taskbar and startmenu pin的更多相关文章

  1. Change the Windows 7 Taskbar Thumbnail and List Mode

    Manually in Registry Editor 1. Open the Start Menu, then type regedit in the search boxand press Ent ...

  2. Scott Hanselman's 2014 Ultimate Developer and Power Users Tool List for Windows -摘自网络

    Everyone collects utilities, and most folks have a list of a few that they feel are indispensable.  ...

  3. Windows 7 Shortcuts (完整兼具分类有序,想我所想,赞!)

    Original Link: http://www.shortcutworld.com/en/win/Windows_7.html Table of Contents: Managing 'Windo ...

  4. Windows Server 2008 R2 小技巧 (转)

    一些 Windows Server 2008 R2 的小技巧,包括启用「God Mode (上帝模式)」.添加「快速启动」工具栏.启用桌面「个性化」服务.停用「密碼複雜性」要求,对老程序员熟悉新版的 ...

  5. .net Framework Class Library(FCL)

    from:http://msdn.microsoft.com/en-us/library/ms229335.aspx 我们平时在VS.net里引用的那些类库就是从这里来的 The .NET Frame ...

  6. win7下Chrome有两个图标的解决方法

    摘抄自:http://www.sevenforums.com/browsers-mail/238406-windows-7-taskbar-creating-double-google-chrome- ...

  7. 卸载oracle删除注册表脚本

    一.前言 在我们操作系统中,有时要卸载oracle数据库,每一次都要去删除win下的注册表,为了方便删除注册表的信息,下面通过一种删除注册表快捷的脚本. 二.脚本信息 Windows Registry ...

  8. MFC程序运行流程

    ->进入入口函数_tWinMain() 程序首先进入文件AppModul.cpp,找到_tWinMain()函数运行,调用其中的AfxWinMain()函数. 由于为了支持UNICODE,C运行 ...

  9. Oracle11g的注册表清理

    每次卸载了oracle总是有一堆注册表没有清理,麻烦,特地在网上找了一个较为完整的,全文复制过来,存自己这里,如下: <<< Windows Registry Editor Vers ...

随机推荐

  1. commons-logging \ log4j \ slf4j 之间的关系

    最近的一个web项目中要使用到日志,但是对常用的日志记录工具(框架)着实不是很理解,在此mark一下. 1.commons-logging.jar common-logging是apache提供的一个 ...

  2. 在Github上搭建你的博客

    title: blog on github date: 2014-03-24 20:29:47 tags: [blog,github,hexo] --- **用Github写博文** 参考http:/ ...

  3. 一維條碼編碼規則(1D Barcode)

    1.Code 39 條碼:又分 標準型Code 39 條碼(Standard Code 39):資料內容包含有0~9數字,A~Z英文字母,”+”,”-“,”*”,”/”,”%”,”$”,”.”以及sp ...

  4. poj 2363 Blocks(暴力)

    题目链接:http://poj.org/problem?id=2363 思路分析:由于数据较小,采用暴力搜索法.假设对于矩形边长 1 <= a <= b <= c <= N; ...

  5. C# Setup package Uninstaller

    安裝的部分就不介紹了,網上一搜一大堆,這裡只介紹下卸載的部分. 1.在C:\Windows\System32 目录下找到 msiexec.exe 拷贝到相应的地方,可修改名称为 Uninstall.e ...

  6. Android Intent 解析之二

    服务端Intent运行过程: Sticky:这个类型的BroadCast表示某些Intent须要被保留,当新的应用起来后,须要关注这个消息,可是呢,又不须要启动这个应用来接收此消息,比方耳机插入等消息 ...

  7. Codeforces 360C Levko and Strings dp

    题目链接:点击打开链接 题意: 给定长度为n的字符串s,常数k 显然s的子串一共同拥有 n(n-1)/2 个 要求找到一个长度为n的字符串t,使得t相应位置的k个子串字典序>s #include ...

  8. Android百度地图定位

    在谈到百度地图.如今,每个人都知道这个时候应该可以了吧.而更多的字不拉.直接朝话题. 访问百度地图api您必须应用key,应用在这里key不用说,有官方的文件说明如何应用上述key. 在这里,百度地图 ...

  9. Linux上传下载文件命令

    转载自http://lupingui.iteye.com/blog/239694 linux系统下可以直接从客户端上传文件到服务器端,命令格式: [plain] view plaincopy scp  ...

  10. docker学习笔记13:Dockerfile 指令 WORKDIR介绍

    Dockerfile中的WORKDIR指令用于指定容器的一个目录, 容器启动时执行的命令会在该目录下执行. 相当于设置容器的工作目录了.我们来看一个dockerfile文件 #test FROM ub ...