IIS8.0上で動作しているDataSnap(64ビットDLL)のサーバーメソッドを呼び出すと、Internal error(HTTP Staus 500)が発生する
対象となるIDE製品
- Delphi XE ~ Delphi XE7
対象となるターゲット環境
- Windows 2012 Server + IIS 8.0
- DataSnap(64ビット)
問題
特定の環境(例えば、Windows 2012 Server+IIS8.0)で動作するDataSnapのISAPI形式の DLL(64ビット)を作成し、クライアントからTObjectから派生しているoutパラメータを含むDataSnapのサーバーメソッドを呼び出すと、Internal error(HTTP Staus 500)が発生することがあります。
以下は、TObjectから派生しているoutパラメータを含むサーバーメソッドの定義の例です。
procedure Method(out value: TObject);
なお、本症状は、例えば、以下のようなケースの場合は、同様のエラーは発生しません。
- サーバーメソッドでoutパラメータを定義していない
- サーバーメソッドのout バラメータをstring型やIntegerなどのプリミティブ型で定義している
- DataSnapのISAPI DLLを32ビットとしてビルド
- Windows 2008 R2+ IIS7.5の環境へDataSnap ISAPI DLLを配置
解決
Windows 2012+ IIS8 (64bit)のISAPI DLL環境では、 デフォルトでハイメモリアドレシングが要求され、そのアドレス空間を使用する必要があります XE7までのDataSnapの仕様では、サーバーメソッドのパラメータがTObject型の場合、バリアントデータからその参照を持つポインタへキャストしており、、そのポインタのデータ長がInteger型(32ビット)になっているため、32ビットを超える高いメモリ空間へアクセスする実装にはなっていませんでした。
本件は、XE8で修正済みです。
XE8以前のバージョンでこの問題を解決するには、以下のユニットファイルを修正し、自身のプロジェクトへ組み込んでください。
修正するファイル名(Datasnap.DSReflect.pas)
(修正前)
function TDSMethodValues.GetVarObject<T>(Value: Variant): T;
var
LObject: TObject;
begin
if TVarData(Value).VType and varByRef <> 0 then
begin
LObject := TObject(Integer(TVarData(Value).VPointer^));
end
else
LObject := TObject(TVarData(Value).VPointer);
PObject(@Result)^ := LObject;
end;
(修正後)
function TDSMethodValues.GetVarObject<T>(Value: Variant): T;
var
LObject: TObject;
begin
if TVarData(Value).VType and varByRef <> 0 then
begin
//LObject := TObject(Integer(TVarData(Value).VPointer^));
LObject := TObject(TVarData(Value).VPointer^); // この部分のコードを追加
end
else
LObject := TObject(TVarData(Value).VPointer);
PObject(@Result)^ := LObject;
end;