3

Moving on from this question: Setting a "nullable" property on a .NET object

Thanks to Olivier for his help so far. I am now using this import for the .NET type library: https://github.com/DelphiWorlds/MiscStuff/blob/master/Test/mscorlib_TLB.pas which is based on v4 of the CLR, as opposed to the antiquated version I was using.

..and I now have this code:

procedure TDotNetObject.SetEnumProperty(const APropertyName: string; const AValue: OleVariant; const ATypeName: string; const AIndex: Integer = -1);
var
  LRes: HRESULT;
  LEnumType, LPropertyType: _Type;
  LInvokeFlags: TOleEnum;
  LArgs: PSafeArray;
  LConvertedValue: OleVariant;
  LPropertyInfo: _PropertyInfo;
  LIndex: PSafeArray;
  LName: WideString;
  LResHex: string;
begin
  LPropertyType := nil;
  LRes := FType.GetProperty(APropertyName, BindingFlags_Instance or BindingFlags_Public or BindingFlags_NonPublic, LPropertyInfo);
  if Succeeded(LRes) then
  begin
    if ATypeName.IsEmpty then
      LPropertyInfo.GetType(LPropertyType)
    else
      LPropertyType := MTDataClr.GetType(ATypeName); // This is a workaround since for obtaining the underlying type
  end;
  if LPropertyType <> nil then
  begin
    // Convert the value to the correct type
    LEnumType := MTDataClr.GetCoreType('System.Enum');
    LInvokeFlags := BindingFlags_InvokeMethod or BindingFlags_Public or BindingFlags_Static;
    LArgs := VariantToPSafeArray(VarArrayOf([LPropertyType, AValue]));
    if Succeeded(LEnumType.InvokeMember_2('ToObject', LInvokeFlags, nil, Null, LArgs, nil, LConvertedValue)) then
    begin
      // ***** Despite the InvokeMember_2 call having "succeeded", LConvertedValue is exactly the same as AValue ****
      if AIndex >= 0 then
        LIndex := VariantToPSafeArray(VarArrayOf([AIndex]))
      else
        LIndex := nil;
      LRes := LPropertyInfo.SetValue(FTarget, LConvertedValue, LIndex);
      if not Succeeded(LRes) then
      begin
        LResHex := IntToHex(LRes);
        Sleep(0);
      end;
    end;
  end;
end;

Everything works up until SetValue. LResHex is '80070057' which apparently equates to ERROR_INVALID_PARAMETER.

Any clues as to where I have gone wrong?

EDIT: As per the comment I added to the code, despite the InvokeMember_2 call having "succeeded", LConvertedValue is exactly the same as AValue. This would explain why the rest does not work. Any clues as to how I might make the ToObject call actually return an "object"?

Dave Nottage
  • 3,411
  • 1
  • 20
  • 57
  • But you did write a successful test, right? Does it still work with the updated mscorlib_TLB.pas? – Olivier Apr 30 '20 at 08:21
  • The "ToObject" succeeds, the SetValue does not, as per the last part of my question. – Dave Nottage May 03 '20 at 23:43
  • your `FTarget` seems to not be initialised anywhere - is that expected? – timur May 06 '20 at 04:05
  • @timur `FTarget` is initialized elsewhere, when `TDotNetObject` is created – Dave Nottage May 06 '20 at 04:16
  • It's possible that the reason why the SetEnumProperty fails is because the property is not supposed to be changed (i.e. it is updated via other means). – Dave Nottage May 07 '20 at 07:45
  • 1
    Does it work with other enums? Does it fail just for that property? – Olivier May 07 '20 at 08:25
  • I'm just speculating here, but: The property might be a computed property OR get-only property. This kind of property does not have a setter, thus you are unable to set its value. – Emanuel Vintilă May 11 '20 at 17:53
  • @Olivier Would you be able to take another look at this question? As per the edit, the ToObject call "succeeds", but does not return the correct value – Dave Nottage Jun 02 '20 at 00:24
  • Well it looks like the enum is converted back to its numerical value... I don't know if there is a solution to this. Maybe you should take another approach, like writing a helper C# DLL? The DLL would do all the dirty work, and Delphi would just call a few functions from that DLL? – Olivier Jun 03 '20 at 07:48
  • @Olivier That might be a solution, however we'd prefer to avoid that – Dave Nottage Jun 03 '20 at 13:11

0 Answers0