dongzong5017 2013-08-27 19:29
浏览 67
已采纳

使用Azure上的PHP从进程外COM组件调用方法

I've written a simple PHP script which instantiates a COM object for an out-of-process (i.e. exe file) COM component and uses it to call a COM method that the component exposes. This COM method very simply quadruples the number passed as the first argument, returning the result in the second argument (passed by reference). The script shown below works successfully on my local development machine on WampServer 2.0 (Apache 2.2.11 / PHP 5.3.1). The COM component is a Win32 executable built using Delphi.

<?php
  // ensure no time limit is imposed
  set_time_limit(0);
  // show all errors, warnings and notices whilst developing
  error_reporting(E_ALL);

  $numIn = 3;
  $numOut = new VARIANT(1, VT_I4);
  echo '----- BEFORE ---------' . '<br>';
  echo 'NumIn: ' . $numIn . '<br>';
  echo 'NumOut: ' . $numOut . '<br>';   
  echo '----------------------' . '<br>';

  $oleapp = new COM("OleAutomationFeasibilityModel.Automation") or die ("Could not initialise feasibility model object.");
  echo '<br />COM object created version = ' . $oleapp->Version . '<br /><br />';
  $oleapp->CalculateWithVariants($numIn, $numOut);
  unset($oleapp);

  echo '----- AFTER ---------' . '<br>';
  echo 'NumIn: ' . $numIn . '<br>';
  echo 'NumOut: ' . $numOut . '<br>';   
  echo '----------------------' . '<br>';   
?>

Note: as I understand it, one can only pass a parameter by reference to a COM method using a VARIANT type, as common data types like integers and strings won't work (see http://www.php.net/manual/en/ref.com.php#45038).

I then created and deployed an Azure Web Role (Cloud Service) with a startup script that registers the COM component successfully i.e. the appropriate registry keys appeared in the registry. To further confirm that the COM component could be interacted with, I used RDP to connect to the cloud service instance and installed Microsoft Access Runtime 2010 as I have an Access application that provides a GUI to test the methods of the COM component. I was able to run this application and successfully interacted with the COM component, using it to pass an integer to the CalculateWithVariants method and the expected quadrupled result was returned. So, I've established that the COM component is installed and can be interacted with on the Azure cloud service instance.

Next I included the above PHP script in the Web Role and deployed it on Azure. Unfortunately, calling the script from a browser results in an HTTP Error 500 (Internal Server Error) and I'm struggling to find out why. If I comment out all lines referencing $oleapp, I still get the same error. If I additionally comment out the line that instantiates a variant object, no error occurs. If I reinstate the line which instantiates the COM object and the line below it, I receive no error message but the only text echoed is from the lines preceding the COM object creation line i.e. the call to the Version method fails. So it appears to be struggling with the variant object creation and the COM object creation.

I'm a bit stuck in terms of how to resolve this issue. I would therefore be very grateful if anyone has any pointers as to a way forward.

UPDATE 1

I decided to try a different course of action on the Azure platform by...

  • creating an Azure Virtual Machine with a Windows Server 2008 R2 OS
  • installing WampServer 2.2E (Apache 2.2.22 / PHP 5.3.13 / MySQL 5.5.24) in the VM as a quick and easy way to test whether this approach would work
  • copying the above PHP script into the WampServer "www directory"
  • launching WampServer
  • selecting the "Put Online" option from the WampServer Menu (accessed by left-clicking the WampServer icon in the Windows Taskbar Notification area)
  • creating an "Inbound Rule" for the VM firewall to allow connections to port 80

...and thankfully the script ran successfully!

Ideally, I would still like to get this working as an Azure cloud service as it shouldn't be necessary for me to maintain the PHP installation in a full VM.

UPDATE 2

I tried restarting the cloud service, then remotely connecting to an instance of the cloud service and looking in the Application Event Viewer. I saw that WMI logged 1 error during startup:

Event filter with query "SELECT * FROM __InstanceModificationEvent WITHIN 60 
WHERE TargetInstance ISA "Win32_Processor" AND TargetInstance.LoadPercentage > 99" 
could not be reactivated in namespace "//./root/CIMV2" because of error 0x80041003 
Events cannot be delivered through this filter until the problem is corrected.

I then ran the above script a couple of times and rechecked the Application Event Viewer but nothing had been logged.

I also checked the IIS logs and the Azure log, startup-tasks-log and startup-tasks-error-log files to no avail.

  • 写回答

1条回答 默认 最新

  • dongye9991 2014-02-02 21:56
    关注

    After giving up on solving this last year. I made another concerted effort to resolve it this week and succeeded!

    I basically needed to (a) enable the php_com_dotnet.dll to allow use of COM and VARIANT classes, and (b) grant default Local Activation permission to IIS_IUSRS to allow access to the COM component. I've listed the detailed steps I took below...

    1. Add a folder called php in the web role's bin folder

    2. As of PHP 5.3.15 / 5.4.5, in order to use the COM and VARIANT classes, the php_com_dotnet.dll needs to be enabled inside of php.ini. Previous versions of PHP enabled these extensions by default (source: http://www.php.net/manual/en/com.installation.php). In the php folder, create a php.ini file containing only the following lines...

      [COM_DOT_NET] 
      extension=php_com_dotnet.dll
      
    3. Create a SetDCOMPermission.reg file in the bin folder which contains the following content, to grant default Local Activation permission to IIS_IUSRS...

      [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\OLE]
      "DefaultLaunchPermission"=hex(3):01,00,04,80,74,00,00,00,84,00,00,00,00,00,\
      00,00,14,00,00,00,02,00,60,00,04,00,00,00,00,00,14,00,1F,00,00,00,01,01,00,\
      00,00,00,00,05,12,00,00,00,00,00,18,00,1F,00,00,00,01,02,00,00,00,00,00,05,\
      20,00,00,00,20,02,00,00,00,00,18,00,0B,00,00,00,01,02,00,00,00,00,00,05,20,\
      00,00,00,38,02,00,00,00,00,14,00,1F,00,00,00,01,01,00,00,00,00,00,05,04,00,\
      00,00,01,02,00,00,00,00,00,05,20,00,00,00,20,02,00,00,01,02,00,00,00,00,00,\
      05,20,00,00,00,20,02,00,00
      

      I don't know if the above registry change will work for everyone, so the process I used is documented here (it essentially involved using a program called RegFromApp to record the changes made to the registry when granting default Local Activation permissions for IIS_IUSRS in COM Security and to save the registry changes as a .reg file into the web role's bin folder).

    4. Copy and paste the out-of-process COM component (OleAutomationFeasibilityModel.exe file) into the bin folder

    5. Create a RegisterOleAutomationFeasibilityModel.cmd file in the bin folder to register the COM component and set the necessary permissions to launch it...

      chcp 1252>NUL
      OleAutomationFeasibilityModel.exe /regserver
      regedit.exe /s SetDCOMPermission.reg
      exit /b 0
      
    6. In the ServiceDefinition.csdef file, insert a reference to the .cmd file immediately before the closing Startup tag...

      <Task commandLine="RegisterOleAutomationFeasibilityModel.cmd" executionContext="elevated" />
      
    7. Publish the web role

    Hope that helps someone in a similar situation!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀