• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
thankgoodness
博客园    首页    新随笔    联系   管理    订阅  订阅

api应用简介2

1、自动打开“我的电脑”

     我的问题是在Win95 or Win98 下,能不能编一个程序实现这样的功能. 该程序先自动打开“我的电脑”, 然后在自动关闭, 然后在模拟按键Alt+F4出现关机界面, 最后在模拟输入"Alt+y"关闭计算机。 能实现的话,如何实现?采用的语言为vc++ 5.0 。谢谢!(wenwp01) 
   
     可以使用SHGetSpecialFolderLocation函数获得“我的电脑”所对应的虚拟文件夹的id。然后使用ShellExecuteEx打开这个虚拟文件夹。
    使用API函数SHGetSpecialFolderLocation。shlobj.h里有SHGetSpecialFolderLocation的原型声明。这个函数可以帮我们找到Windows的桌面目录、启动目录、我的文档目录等。
    SHGetSpecialFolder需要三个参数。 第一个参数是HWND,它指定了"所有者窗口":在调用这个函数时可能出现的对话框或消息框。第二个参数是一个整数id,决定哪个目录是待查找目录,它的取值可能是:
     CSIDL_BITBUCKET 回收站
CSIDL_CONTROLS 控制面板
CSIDL_DESKTOP Windows 桌面Desktop
CSIDL_DESKTOPDIRECTORY Desktop的目录
CSIDL_DRIVES 我的电脑
CSIDL_FONTS 字体目录
CSIDL_NETHOOD 网上邻居
CSIDL_NETWORK 网上邻居虚拟目录
CSIDL_PERSONAL 我的文档
CSIDL_PRINTERS 打印机
CSIDL_PROGRAMS 程序组
CSIDL_RECENT 最近打开的文档
CSIDL_SENDTO “发送到”菜单项
CSIDL_STARTMENU 任务条启动菜单项
CSIDL_STARTUP 启动目录
CSIDL_TEMPLATES 文档模板

    这里只是最常用的部分。完整的请参考http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp。
    最后一个参数是pidl地址。SHGetSpecialFolderLocation把地址写到pidl。
    下面是一个例子:
    LPITEMIDLIST pidl;
    TCHAR szPath [MAX_PATH];
    LPMALLOC pMalloc;
    
    if ( SUCCEEDED( SHGetSpecialFolderLocation ( NULL, CSIDL_DRIVES, &pidl )))
    {
     SHELLEXECUTEINFO sei;
     ZeroMemory(&sei, sizeof(sei));
     sei.cbSize = sizeof(sei);
     sei.fMask = SEE_MASK_IDLIST;
     sei.lpIDList = pidl;
     sei.lpVerb = "open";
     sei.hwnd = AfxGetMainWnd()->GetSafeHwnd();
     sei.nShow = SW_SHOWNORMAL;
     ShellExecuteEx(&sei);
     if ( SUCCEEDED( SHGetMalloc ( &pMalloc )))
     {
     pMalloc->Free ( pidl );
     pMalloc->Release();
     }
    }
    
    由于“我的电脑”是虚拟文件夹,所以必须使用ShellExecuteEx函数,如果是普通文件夹,则可以使用SHGetPathFromIDList获得文件名,然后利用ShellExecute函数打开。例如要打开“发送到”文件夹,可以这样:
    if ( SUCCEEDED( SHGetSpecialFolderLocation ( NULL, CSIDL_SENDTO, &pidl )))
    {
     if ( SHGetPathFromIDList ( pidl, szPath ))
     {
     ShellExecute(AfxGetMainWnd()->GetSafeHwnd(),
     "open", szPath, NULL, NULL,
     SW_SHOWNORMAL);
     }
    
     if ( SUCCEEDED( SHGetMalloc ( &pMalloc )))
     {
     pMalloc->Free ( pidl );
     pMalloc->Release();
     }
    }
    
    
    如果是虚拟文件夹,SHGetPathFromIDList函数会失败。
    对于普通文件夹也可以使用SHGetSpecialFolderPath函数,而不使用SHGetSpecialFolderLocation函数,这样更简单些,但运行环境必须是Windows 2000以后的操作系统或安装了IE 4.0以上版本。
    关闭窗口和关机参考QA000166 "如何利用VB实现操作系统或者某一应用程序的自动关闭"。
    
***************************************************
 2、如何使我的进程有超级用户的权限

    问题:我想利用
     hThread = OpenThread(THREAD_TERMINATE, FALSE, dwThreadid);//te32.th32ThreadID);
     Re = GetLastError();
    
    来停止一个知道了线程ID号的线程,但总是返回错误号5(Access is denied)
    是我的进程的权限不够,能告诉我如何使我的进程有超级用户的权限,谢谢! 
   
     li_xf的意见:
    首先使用LogonUser函数创建一个token.
    根据调用参数,有可能需要调用 DuplicateTokenEx 函数,将impersonation token 转换为a primary token.
    
    然后使用这个token 调用CreateProcessAsUser函数,创建一个拥有该用户安全上下文(context)的进程.
    (具体例子详见MSDN)
    
    函数原型:
    BOOL LogonUser(
     LPTSTR lpszUsername,
     LPTSTR lpszDomain,
     LPTSTR lpszPassword,
     DWORD dwLogonType,
     DWORD dwLogonProvider,
     PHANDLE phToken
    );
    BOOL CreateProcessAsUser(
     HANDLE hToken,
     LPCTSTR lpApplicationName,
     LPTSTR lpCommandLine,
     LPSECURITY_ATTRIBUTES lpProcessAttributes,
     LPSECURITY_ATTRIBUTES lpThreadAttributes,
     BOOL bInheritHandles,
     DWORD dwCreationFlags,
     LPVOID lpEnvironment,
     LPCTSTR lpCurrentDirectory,
     LPSTARTUPINFO lpStartupInfo,
     LPPROCESS_INFORMATION lpProcessInformation
    );
    BOOL DuplicateTokenEx(
     HANDLE hExistingToken,
     DWORD dwDesiredAccess,
     LPSECURITY_ATTRIBUTES lpTokenAttributes,
     SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
     TOKEN_TYPE TokenType,
     PHANDLE phNewToken
    );
    
 ************************************************
3、GetTickCount()函数精确到多少毫秒
GetTickCount()和GetCurrentTime()都只精确到55ms(1个tick就是55ms)。如果要精确到毫秒,应该使用timeGetTime函数或QueryPerformanceCounter函数。具体例子可以参考QA001022 "VC++中使用高精度定时器"、QA001813 "如何在Windows实现准确的定时"和QA004842 "timeGetTime函数延时不准"。
 
*************************************************
4、如何用VB或VC对Win 95及NT的注册文件进行读写
 Win 95及NT的注册数据库(Registry)是系统中非常重要的组成部分。在Win32 API中有一组Reg函数来处理这些问题。其一般的读写过程如下:
    1、使用RegOpenKeyEx或RegCreateKeyEx函数打开或创建一个键;
    2、如果上一步成功,使用RegQueryValueEx读取子键的值,使用RegSetValueEx设置子键值,使用RegEnumKey获得所有子键,使用RegDeleteKey删除一个键;
    3、完成操作后使用RegCloseKey关闭键。
    下面这段程序打开HKEY_CURRENT_USER\Software\Zeal SoftStudio\AskPro FTP\LastTime键,然后读取WOL子键的值。
     HKEY hkey;
     char sz[256];
     DWORD dwtype, sl = 256;
    
     RegOpenKeyEx(HKEY_CURRENT_USER,
     "Software\\Zeal SoftStudio\\AskPro FTP\\LastTime",
     NULL, KEY_ALL_ACCESS, &hkey);
     RegQueryValueEx(hkey, "WOL", NULL, &dwtype, (LPBYTE)sz, &sl);
     RegCloseKey(hkey);
    
    MFC程序可以使用CRegKey类读写注册表。
    VB中调用API的办法可以参考QA000226 "如何访问Windows系统注册表"。
    
*************************************************
5、回调函数的内在机制如何
    编程工具: C++ BUILDER 3.0
    操作系统: WIN98
    我想在C++ 中使用回调函数,请问它的内在机制如何,另外怎么定义。我用DialogBox函数时,如何使用回调函数? 它和钩子函数有何不同?多谢指教!!!拜托!!!

A回答:

    使用回调函数实际上就是在调用某个函数(通常是API函数)时,将自己的一个函数(这个函数为回调函数)的地址作为参数传递给那个函数。而那个函数在需要的时候,利用传递的地址调用回调函数,这时你可以利用这个机会在回调函数中处理消息或完成一定的操作。至于如何定义回调函数,跟具体使用的API函数有关,一般在帮助中有说明回调函数的参数和返回值等。C++中一般要求在回调函数前加CALLBACK,这主要是说明该函数的调用方式。DialogBox的回调函数实际上是个窗口过程,用来处理所有消息。其定义为:
    BOOL CALLBACK DialogProc(
    
     HWND hwndDlg, // handle of dialog box
     UINT uMsg, // message
     WPARAM wParam, // first message parameter
     LPARAM lParam // second message parameter
     );
    在Win32 API中有详细说明。一般使用C++ Builder或MFC的往往没有使用SDK编程的经验,建议找一些SDK编程的书看一下,否则很难理解如何使用窗口过程。
    至于钩子函数,只是回调函数的一个特例。习惯上把与SetWindowsHookEx函数一起使用的回调函数称为钩子函数。也有人把利用VirtualQueryEx安装的函数称为钩子函数,不过这种叫法不太流行。
    
    frank的意见:
    我对回调函数的理解虽然粗浅,但是我觉得会让人更容易理解:回调函数就相当于一个中断处理函数,由系统在符合你设定的条件时自动调用。为此,你需要做三件事:1,声明;2,定义;3,设置触发条件,就是在你的函数中把你的回调函数名称转化为地址作为一个参数,以便于系统调用。
    声明和定义时应注意:回调函数由系统调用,所以可以认为它属于WINDOWS系统。不要把它当作你的某个类的成员函数。
    
    ping的意见:
    frank说:回调函数属于WINDOWS系统。我觉得不应该说回调函数是属于系统的。应该说是程序把这段代码的触发交由系统来做。而这种做法是WINDOWS提供的处理机制吧,因为消息是系统一手掌握着的,由系统来调用我们的程序对消息的处理部分,这样子会比较方便。不然我们又得花力气去读消息列表了。(不知道我说的对不对,接触系统还不深,请高手指教哦)

 *************************************************
6、如何获得其他运行的应用程序发出的消息

如何获得其他运行的应用程序发出的消息?

回答:

    一般是利用API函数SetWindowsHookEx来建立钩子函数,这样Windows在处理消息之前会将消息传递给钩子函数。Windows截取消息分为两种:线程和系统。线程方式只能截取当前线程消息,而系统方式可以获得所有消息。如果要实现系统方式,需要调用API函数SetWindowsHookEx,如:
    SetWindowsHookEx(WH_MOUSE, MyHooProc, 0, 0);
    但这种方式必须编写一个标准DLL。
    在VC++中有一个Spy的例子(在MSDN\Samples\VC98\sdk\sdktools\spy\目录),它的具体功能就是Spy++的工作,你可以参考。
    另外,可以参考QA000888

"怎样使用钩子函数"。

***********************************************
 
在Win32 API中有详细的关于钩子函数的介绍,如果你没有Win32 API,可以参考QA000150 "哪里能够找到WIN95 API的资料"。
    Windows的钩子函数分两种,一种是全局的,一种是线程的。全局的钩子函数可以捕获任何应用程序的消息,但必须是标准的DLL才能实现,VB做不了。VB可以实现线程的,就是当前应用程序的消息,这对鼠标消息的捕捉有影响。
    SetWindowsHookEx定义如下:
    Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
    idHook是钩子类型,如WH_KEYBOARD捕捉键盘消息,而WH_MOUSE捕捉鼠标消息。hmod用于全局钩子,VB要实现钩子,必须设为0。dwThreadId用于线程钩子VB中可以设置为App.ThreadID。lpfn为钩子函数,在VB中可以使用AddressOf获得钩子函数的地址。这个函数因为钩子类型不同而有所不同。如键盘钩子为:
    Public Function KeyboardProc(ByVal nCode As Long, _
     ByVal wParam As Long, _
     ByVal lParam As Long) As Long
    如果Code不为0,钩子函数必须调用CallNextHookEx,将消息传递给下面的钩子。wParam和lParam不是按键。
    你可以在微软的Knowledge Base的文章:“Q180936 OWTO: Position a MsgBox Using a Windows Hook Procedure”、微软的Knowledge Base的文章:“Q177992 OWTO: Intercept Keyboard Input from Visual Basic”和找到VB使用钩子函数的例子。

posted @ 2009-03-30 17:27  宇晨  阅读(299)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3