私は得ています
com_exception: Error [0x80070057] The parameter is incorrect.
私のphpスクリプトから(コマンドラインで実行)。C#で書いたCOMサーバーを呼び出しています。
動作している C++ クライアントもあります。
SAFEARRAY
PHPで文字列 (BSTR) を COM 関数に渡す正しい方法がわかりません。
C++ クライアントでは、DoArray 関数には次のシグネチャがあります: DoArray(SAFEARRAY **)
. PHP クライアントは8204
、 を呼び出してバリアント タイプを報告しましたvariant_get_type($ary)
。
コード 8204 はVT_ARRAY | VT_BSTR
、BSTR の SAFEARRAY を意味するようです。BSTR の SAFEARRAY を渡しているのに、「パラメータが正しくありません」というエラーが表示されるのは奇妙に思えます。
参考までにPHPcom_print_typeinfo()
を載せておきます。の出力でcom_print_typeinfo
、何が何であるか理解できません
/* VT_PTR [26] [in] --> VT_SAFEARRAY [27] */ &$ary
.
関連する PHP バグ # 48061 php バグ 48061を見てきました。誰かがそのバグに応答しましたか?
Windows 、.NET Framework 4 、および Windows 7 に PHP 5.3.8 (非スレッドセーフ) を使用しています。
生成された IDL ファイル
// Generated .IDL file (by the OLE/COM Object Viewer)
//
// typelib filename: FanCom.tlb
[
uuid(2F0E398B-E218-467D-8B9B-732E24F07780),
version(1.0),
custom(90883F05-3D28-11D2-8F17-00A0C9A6186D, "FanCom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5066ce5e2963d76a")
]
library FanCom
{
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
// Forward declare all types defined in this typelib
dispinterface IFanFan;
[
uuid(252B2B91-70FE-4A20-BCF6-3693CE7849D4),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "FanCom.IFanFan")
]
dispinterface IFanFan {
properties:
methods:
[id(0x60020000)]
BSTR Echo([in] BSTR str);
[id(0x60020001)]
BSTR DoArray([in] SAFEARRAY(BSTR)* ary);
};
[
uuid(0AF61517-E479-4F96-A20E-1D040651C05C),
version(1.0),
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "FanCom.FanFan")
]
coclass FanFan {
interface _Object;
[default] dispinterface IFanFan;
[default, source] dispinterface IFanFan;
};
};
C# COM 相互運用コード (上記の IDL コードに対応)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace FanCom
{
[Guid("252B2B91-70FE-4A20-BCF6-3693CE7849D4")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IFanFan
{
string Echo(string str);
string DoArray([In] ref string[] ary);
}
[ClassInterface(ClassInterfaceType.None)] // No ClassInterface
[ComSourceInterfaces(typeof(IFanFan))]
[Guid("0AF61517-E479-4F96-A20E-1D040651C05C")] // CLSID
[ComVisible(true)]
public class FanFan : IFanFan
{
public string Echo(string str)
{
return string.Format("Hello {0}", str);
}
public string DoArray(ref string[] ary)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < ary.Length; ++i)
{
builder.Append(ary[i]);
builder.Append(",");
}
return builder.ToString();
}
}
}
COM を使用するための PHP クライアント
<?php
echo "started <br/>\n";
$com = new COM("FanCom.FanFan");
echo "com created <br/>\n";
com_print_typeinfo($com);
$s = $com->Echo("Dan");
echo "$s <br/> \n";
//$ary = new VARIANT(array("a", "b", "c") , VT_ARRAY|VT_BSTR);
//$ary = array("a", "b");
//$ary = new VARIANT(array(new VARIANT("a", VT_BSTR), new VARIANT("b", VT_BSTR)), VT_ARRAY|VT_BYREF|VT_BSTR);
//$ary = new VARIANT(array(new VARIANT("a", VT_BSTR), new VARIANT("b", VT_BSTR)), VT_ARRAY|VT_VARIANT);
//$ary = array(new VARIANT("a", VT_BSTR), new VARIANT("b", VT_BSTR));
//$x = new VARIANT(array(new VARIANT("a", VT_BSTR), new VARIANT("b", VT_BSTR)), VT_ARRAY);
//$ary = new VARIANT($x , VT_BYREF|VT_VARIANT);
//$ary = new VARIANT(array('a', 'b') , VT_ARRAY);
//$ary = new VARIANT(array(new VARIANT("a", VT_BSTR), new VARIANT("b", VT_BSTR)), VT_ARRAY);
//$ary = array(new VARIANT("a", VT_BSTR), new VARIANT("b", VT_BSTR));
$ary = new VARIANT(array('a', 'b'), VT_ARRAY);
print variant_get_type($ary);
print "\n";
echo "variant created <br/> \n";
$s1 = $com->DoArray($ary);
echo "$s1 <br/> \n";
echo "end";
?>
PHP com_print_typeinfo 出力
class IFanFan { /* GUID={252B2B91-70FE-4A20-BCF6-3693CE7849D4} */
/* DISPID=1610743808 */
/* VT_BSTR [8] */
function Echo(
/* VT_BSTR [8] [in] */ $str
)
{
}
/* DISPID=1610743809 */
/* VT_BSTR [8] */
function DoArray(
/* VT_PTR [26] [in] --> VT_SAFEARRAY [27] */ &$ary
)
{
}
}
COM を呼び出す C++ クライアント
#include <cstdio>
#include <conio.h>
#include "stdafx.h"
#import "C:\Project\FanCom\FanCom\bin\Debug\FanCom.tlb"
#include <oaidl.h>
void CreateSafeArray(SAFEARRAY** saData)
{
bstr_t data[3] = {bstr_t(L"a") , bstr_t(L"b") , bstr_t(L"c") };
SAFEARRAYBOUND Bound;
Bound.lLbound = 0;
Bound.cElements = 3;
*saData = SafeArrayCreate(VT_BSTR, 1 , &Bound);
BSTR HUGEP *pdFreq;
HRESULT hr = SafeArrayAccessData(*saData, (void HUGEP* FAR*)&pdFreq);
if (SUCCEEDED(hr))
{
// copy sample values from data[] to this safearray
for (DWORD i = 0; i < Bound.cElements; ++i)
{
*pdFreq++ = data[i].GetBSTR();
}
SafeArrayUnaccessData(*saData);
//SafeArrayUnaccessData(saData);
}
}
HRESULT ImportCSharpComponent()
{
HRESULT hr = S_OK;
::CoInitialize(NULL);
try
{
FanCom::IFanFanPtr spSimpleObj;
hr = spSimpleObj.CreateInstance(__uuidof(FanCom::FanFan));
if (FAILED(hr))
{
wprintf(L"FanCom::IFanFanPtr failed w/err 0x%08lx\n", hr);
return hr;
}
{
bstr_t bstrInput("Derek");
bstr_t outString = spSimpleObj->Echo(bstrInput);
wprintf(L"%s\n", (PCWSTR)outString);
}
{
SAFEARRAY* data;
CreateSafeArray((SAFEARRAY **)&data);
bstr_t ret = spSimpleObj->DoArray((SAFEARRAY **)&data);
wprintf(L"DoArray() return %s\n", (PCWSTR)ret);
SafeArrayDestroy(data);
data = NULL;
}
wprintf(L"\n");
}
catch (_com_error &err)
{
wprintf(L"The server throws the error: %s\n", err.ErrorMessage());
wprintf(L"Description: %s\n", (PCWSTR) err.Description());
}
// Uninitialize COM for this thread
::CoUninitialize();
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT h = ImportCSharpComponent();
return 0;
}