创建 ATL COM DLL 并通过 PHP 调用它
演示如何创建简单的ATL COM DLL并通过PHP调用它。
引言
有时您可能需要从PHP获得对底层操作系统的更大访问权限。本文演示了一种实现上述目的的技术的基本步骤,即创建ATL COM DLL、注册它,最后通过运行Apache Web服务器的Windows环境中的PHP来调用它。
要求
要求列出了用于创建和测试演示版的软件,除非特别说明,否则不一定排除相同软件的其他版本。
- Windows XP 专业版
- Apache 2.0.54 Web服务器
- PHP 5.2.6.(在早期版本中,会触发oleaut32.dll中的访问冲突)
- Visual Studio .NET Professional
创建ATL COM DLL
在接下来的步骤中,我们将创建一个具有一个类和两个成员方法的ATL COM DLL,一个用于检索当前正在使用的物理内存的近似百分比,第二个用于重新启动主机计算机。
- 启动Visual Studio .NET
- 启动“新建项目”
- 选择“Visual C++ 项目”
- 选择“ATL 项目”
- 点击“确定”
- 将项目命名为“ATLDemo”
- 点击“确定”
- 由于默认选项是“动态链接库(DLL)”,请点击“完成”
Visual Studio .NET现在将生成项目,我们已准备好继续。
- 右键单击项目名称
- 转到“添加”选项
- 选择“添加类…”
- 选择“ATL简单对象”
- 点击“打开”
- 为短名称输入“MyClass”
- 点击“完成”,我们将接受所有默认选项
我们的新类现已添加,您可能会注意到系统也为我们生成了一个接口类,在本例中名为IMyClass
。下一步,我们将按照以下步骤添加我们的两个成员方法:
- 右键单击名为“
IMyClass
”的接口类 - 转到“添加”
- 选择“添加方法”
- 为方法名称输入
GetMemoryLoad
- 在“参数属性”部分下选中“in”复选框
- 为参数类型选择
VARIANT*
- 将参数命名为“
vtMemoryLoad
” - 点击“添加”
- 点击“完成”
新成员方法现已添加,下一步我们将为其添加代码
STDMETHODIMP CMyClass::GetMemoryLoad(VARIANT* vtMemoryLoad)
{
// Create an instance of the MEMORYSTATUSEX structure
MEMORYSTATUSEX memstatex;
// Specify the length of the structure
memstatex.dwLength = sizeof(memstatex);
// Call the GlobalMemoryStatusEx function and pass to it
// a reference to our MEMORYSTATUSEX instance
::GlobalMemoryStatusEx(&memstatex);
// Set the ulVal (unsigned long value) of the VARIANT parameter
// passed by reference to the function with the dwMemoryLoad
// value of the MEMORYSTATUEX instance which specifies the
// approximate percentage of the physical memory currently
// in use.
vtMemoryLoad->ulVal = memstatex.dwMemoryLoad;
return S_OK;
}
我们将重复步骤1-9,以便将第二个函数作为此演示的一部分添加。
- 右键单击名为“
IMyClass
”的接口类 - 转到“添加”
- 选择“添加方法”
- 为方法名称输入
RestartHost
- 在“参数属性”部分下选中“in”复选框
- 为参数类型选择
VARIANT*
- 将参数命名为“
vtLastError
” - 点击“添加”
- 点击“完成”
将以下代码添加到新函数中
STDMETHODIMP CMyClass::RestartHost(VARIANT* vtLastError)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// In order to be able to restart the local computer we need the
// SE_SHUTDOWN_NAME privilege, in the following steps we will
// retrieve the privileges of the current process and enable
// the SE_SHUTDOWN_NAME privilege
if(::OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
// If the adjusting of the privilege succeeded
if(::GetLastError() == ERROR_SUCCESS) {
// Initiate the system restart, note the fourth argument will
// force the shutdown of all applications, when testing please
// ensure that you have no unsaved data as it might be lost.
// The fifth argument will restart the computer.
::InitiateSystemShutdown(NULL, _T("ATL COM DLL/PHP Demo"), 0, TRUE, TRUE);
}
}
// Set the ulVal (unsigned long value) of the VARIANT parameter
// to the value returned by GetLastError as this might be useful in
// troubleshooting.
vtLastError->ulVal = ::GetLastError();
return S_OK;
}
下一步,我们将编译DLL。默认情况下,项目将保持Debug模式,在成功编译并进行彻底测试后,我们可以在部署DLL之前将其切换到Release模式。为了进行此演示,我们将立即这样做。
- 在菜单上点击“项目”
- 点击“ATLDemo属性”
- 将“配置:”选项更改为“Release”
- 点击“确定”
- 在菜单上点击“生成”
- 点击“重新生成解决方案”
这标志着创建我们的示例ATL COM DLL的过程结束。
注册ATL COM DLL
现在我们已经创建了ATL COM DLL,下一步是注册它,以便通过COM接口供其他应用程序使用。
- 通过浏览到项目的“Release”目录来定位DLL,或者通过名称搜索DLL,在本例中为“ATLDemo.dll”。
- 将DLL移动到其最终目的地,在本例中,我们将DLL放入“C:\WINDOWS\system32”目录。
- 通过命令行调用REGSVR32实用程序来注册DLL。
- 点击“开始”
- 点击“运行”
- 输入“CMD”
- 在命令提示符下,输入:REGSVR32 "C:\WINDOWS\system32\ATLDemo.dll"
- 您应该会看到一个消息框,告知您注册已成功。
这标志着注册我们的示例ATL COM DLL并使其可供COM感知应用程序使用的过程结束。
通过PHP调用ATL COM DLL
在本节中,我们将编写一个PHP页面来调用我们新创建的ATL COM DLL并使用它。请注意,此时,我们假定您在Windows环境中运行Apache Web服务器。在此演示中,Apache Web服务器作为可执行文件在一个具有完全管理员权限的帐户下运行。安全设置可能会造成障碍,具体取决于您的Web服务器配置,例如,如果您将Apache Web服务器作为服务在一个权限不足的帐户下运行,则要创建COM对象,您需要调整该帐户的权限。运行IIS而不是Apache也是如此;然而,由于这是一篇简单的概念文章,因此不对安全设置进行详细讨论。
Windows版PHP在其核心功能中提供了调用COM对象的能力。有关详细信息,请参阅http://us.php.net/com。
我们的第一步是识别类的ProgID
,以便能够实例化该类的实例;最简单的方法是通过访问注册表并了解其值。
- 点击“开始”
- 点击“运行”
- 输入REGEDIT
- 点击“确定”
- 在
HKEY_CLASSES_ROOT
下,找到DLL的名称。 - 已找到并确定值为
ATLDemo.MyClass
。
接下来,我们将编写PHP代码,该代码将创建类的实例,立即显示可用物理内存的近似百分比,并提供重新启动主机计算机的功能。
<?php
// Create an instance of our COM object
$obj = new COM("ATLDemo.MyClass");
// Create an instance of the VARIANT structure,
// initial value 0,
// VT_UI4 (data type, see VARIANT data structure for details)
$vtMemoryLoad = new VARIANT(0, VT_UI4);
// Retrieve the current memory load
$obj->GetMemoryLoad($vtMemoryLoad);
print '<p>Physical memory in use : '.$vtMemoryLoad.'%</p>';
// If the "Restart Host" button was pressed
if($_POST['btnRestart']) {
// VARIANT to restore the value returned by the GetLastError() function
$vtLastError = new VARIANT(0, VT_UI4);
// Initiate host restart
$obj->RestartHost($vtLastError);
print '<p>Initiated host restart...</p>';
print '<p>Last Error Code: '.$vtLastError.'</p>';
}
?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">
<input type="submit" value="Restart Host"
name="btnRestart" id="btnRestart" />
</form>
- 将文件另存为“index.php”,放在新的Web服务器目录中。
- 通过浏览器运行它。
- 注意内存使用值,后续的页面访问将根据使用情况改变输出。
- 点击“重启主机”按钮来重启计算机(注意:请在测试前保存任何待处理的工作)。
结论
非常感谢您阅读本文。我希望本文或其中至少某些方面可能对您有所帮助。建设性的批评是受到赞赏的,并将予以考虑。