لماذا مفهرس على بلدي .صافي مكون ليس دائما يمكن الوصول إليها من VBScript?

StackOverflow https://stackoverflow.com/questions/317759

  •  11-07-2019
  •  | 
  •  

سؤال

لدي .صافي الجمعية التي أنا الوصول من VBScript (ASP الكلاسيكية) عبر COM إمكانية التشغيل المتداخل.فئة واحدة لديها المفهرس (أ.ك.أ.الخاصية الافتراضية) التي حصلت العمل من VBScript بإضافة السمة التالية إلى المفهرس: [DispId(0)].يعمل في معظم الحالات, ولكن ليس عند الوصول إلى الطبقة كعضو من كائن آخر.

كيف يمكنني الحصول على عمل مع بناء الجملة التالي: Parent.Member("key") حيث عضو المفهرس (مماثلة إلى الوصول إلى الخاصية الافتراضية المدمج في Request.QueryString: Request.QueryString("key"))?

في حالتي, هناك فئة الأم TestRequest مع QueryString الممتلكات التي بإرجاع IRequestDictionary, الذي الافتراضي مفهرس.

VBScript على سبيل المثال:

Dim testRequest, testQueryString
Set testRequest = Server.CreateObject("AspObjects.TestRequest")
Set testQueryString = testRequest.QueryString
testQueryString("key") = "value"

السطر التالي يسبب خطأ بدلا من طباعة "قيمة".هذه هي الجملة أود أن الحصول على العمل:

Response.Write(testRequest.QueryString("key"))

Microsoft VBScript runtime (0x800A01C2)
عدد خاطئ من الحجج أو غير صالح المنشأة المهمة:'QueryString'

ومع ذلك ، ما يلي هل العمل دون خطأ والمخرجات المتوقعة "القيمة" (لاحظ أن السطر الأول بالوصول الافتراضي مفهرس على متغير مؤقت):

Response.Write(testQueryString("key"))
Response.Write(testRequest.QueryString.Item("key"))

أدناه هي تبسيط واجهات دروس في C# 2.0.وقد تم تسجيلها عبر RegAsm.exe /path/to/AspObjects.dll /codebase /tlb:

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IRequest {
    IRequestDictionary QueryString { get; }
}

[ClassInterface(ClassInterfaceType.None)]
public class TestRequest : IRequest {
    private IRequestDictionary _queryString = new RequestDictionary();

    public IRequestDictionary QueryString {
        get { return _queryString; }
    }
}

[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IRequestDictionary : IEnumerable {
    [DispId(0)]
    object this[object key] {
        [DispId(0)] get;
        [DispId(0)] set;
    }
}

[ClassInterface(ClassInterfaceType.None)]
public class RequestDictionary : IRequestDictionary {
    private Hashtable _dictionary = new Hashtable();

    public object this[object key] {
        get { return _dictionary[key]; }
        set { _dictionary[key] = value; }
    }
}

لقد حاولت البحث والتجريب مع خيارات مختلفة ولكن حتى الآن لم يجدوا حلا.سيكون موضع تقدير أي مساعدة لمعرفة السبب testRequest.QueryString("key") الجملة لا يعمل و كيفية الحصول على عمل.

ملاحظة:هذا هو متابعة وفضح مفهرس / الخاصية الافتراضية عبر Interop COM.

تحديث:هنا بعض ولدت IDL من مكتبة نوع (باستخدام oleview):

[
  uuid(C6EDF8BC-6C8B-3AB2-92AA-BBF4D29C376E),
  version(1.0),
  custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, AspObjects.IRequest)

]
dispinterface IRequest {
    properties:
    methods:
        [id(0x60020000), propget]
        IRequestDictionary* QueryString();
};

[
  uuid(8A494CF3-1D9E-35AE-AFA7-E7B200465426),
  version(1.0),
  custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, AspObjects.IRequestDictionary)

]
dispinterface IRequestDictionary {
    properties:
    methods:
        [id(00000000), propget]
        VARIANT Item([in] VARIANT key);
        [id(00000000), propputref]
        void Item(
                        [in] VARIANT key, 
                        [in] VARIANT rhs);
};
هل كانت مفيدة؟

المحلول

وعثر عليها في هذا المشكلة بالضبط قبل أيام قليلة. لم أجد تفسيرا معقولا لماذا لا يعمل.

وبعد قضاء ساعات طويلة في محاولة الحلول المختلفة، وأعتقد أنني أخيرا وجدت شيء يبدو للعمل، وليس قذرة جدا. ما فعلته هو تنفيذ استرجاع إلى المجموعة في كائن حاوية كوسيلة من وسائل، بدلا من خاصية. يتلقى هذا الأسلوب وسيطة واحدة، المفتاح. إذا كان المفتاح هو "مفقود" أو باطل، ثم الأسلوب بإرجاع مجموعة (هذا يعالج عبارات مثل "testRequest.QueryString.Count" في VBScript). خلاف ذلك، فإن الأسلوب بإرجاع عنصر معين من المجموعة.

والجزء القذرة مع هذا النهج هو أن هذا الأسلوب بإرجاع كائن (لأن في بعض الأحيان الإشارة العائد هو جمع، وأحيانا عنصر من المجموعة)، لذلك استخدامه من التعليمات البرمجية المدارة يحتاج الصب في كل مكان. لتجنب هذا، أنا خلق ممتلكات أخرى (هذه المرة خاصية المناسبة) في حاوية الذي يعرض المجموعة. لا يتعرض هذه الخاصية لCOM. من C # / التعليمات البرمجية المدارة يمكنني استخدام هذه الخاصية، ومن / فبسكريبت / القانون COM غير المدارة يمكنني استخدام هذه الطريقة.

وهنا هو تنفيذ للمشكلة أعلاه باستخدام مثال على هذا الموضوع:

  [ComVisible(true)]
  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  public interface IRequest
  {
    IRequestDictionary ManagedQueryString { get; } // Property to use form managed code
    object QueryString(object key); // Property to use from COM or unmanaged code
  }

  [ComVisible(true)]
  [ClassInterface(ClassInterfaceType.None)]
  public class TestRequest : IRequest
  {
    private IRequestDictionary _queryString = new RequestDictionary();

    public IRequestDictionary ManagedQueryString
    {
      get { return _queryString; }
    }

    public object QueryString(object key)
    {
      if (key is System.Reflection.Missing || key == null)
        return _queryString;
      else
        return _queryString[key];
    }
  }

  [ComVisible(true)]
  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  public interface IRequestDictionary : IEnumerable
  {
    [DispId(0)]
    object this[object key]
    {
      [DispId(0)]
      get;
      [DispId(0)]
      set;
    }

    int Count { get; }
  }

  [ComVisible(true)]
  [ClassInterface(ClassInterfaceType.None)]
  public class RequestDictionary : IRequestDictionary
  {
    private Hashtable _dictionary = new Hashtable();

    public object this[object key]
    {
      get { return _dictionary[key]; }
      set { _dictionary[key] = value; }
    }

    public int Count { get { return _dictionary.Count; } }

    #region IEnumerable Members

    public IEnumerator GetEnumerator()
    {
      throw new NotImplementedException();
    }

    #endregion
  }

نصائح أخرى

ونتائج التحقيق الخاص بي على هذا الموضوع:

والمشكلة هي النسبية لتطبيق IDispatch يستخدم وقت تشغيل اللغة العامة عند تعريض اجهات المزدوجة وdispinterfaces إلى COM.

ولغة البرمجة مثل فبسكريبت (ASP) استخدام تنفيذ OLE أتمتة IDispatch وعند الوصول إلى كائن COM.

وعلى الرغم من أنه يبدو للعمل، وأريد للحفاظ على الممتلكات كخاصية ولا تريد أن يكون لها وظيفة (الحل شرح أعلاه).

لديك 2 الحلول الممكنة:

1 - استخدام IDispatchImplAttribute إهمال مع IDispatchImplType.CompatibleImpl

    [ClassInterface(ClassInterfaceType.None)]
    [IDispatchImpl(IDispatchImplType.CompatibleImpl)]
    public class TestRequest : IRequest
    {
        private IRequestDictionary _queryString = new RequestDictionary();
        public IRequestDictionary QueryString
        {
            get { return _queryString; }
        }
    }

وكما قال في MSDN، تم إهمال هذه السمة ولكن لا تزال تعمل مع صافي 2.0، 3.0، 3.5، 4.0. عليك أن تقرر ما إذا كان حقيقة أنه هو "إهمال" يمكن أن يكون مشكلة بالنسبة لك ...

2 - أو تنفيذ IReflect باعتباره IDispatch والعرف في TesRequest صفك أو إنشاء فئة العامة التي تنفذ IReflect وجعل صفك يرث هذا الجديد تسبب في واحدة

وعينة الفئة عام (الجزء إينتيريستينج في أسلوب InvokeMember):

[ComVisible(false)]
public class CustomDispatch : IReflect
{
    // Called by CLR to get DISPIDs and names for properties
    PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr)
    {
        return this.GetType().GetProperties(bindingAttr);
    }

    // Called by CLR to get DISPIDs and names for fields
    FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr)
    {
        return this.GetType().GetFields(bindingAttr);
    }

    // Called by CLR to get DISPIDs and names for methods
    MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr)
    {
        return this.GetType().GetMethods(bindingAttr);
    }

    // Called by CLR to invoke a member
    object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
    {
        try
        {
            // Test if it is an indexed Property
            if (name != "Item" && (invokeAttr & BindingFlags.GetProperty) == BindingFlags.GetProperty && args.Length > 0 && this.GetType().GetProperty(name) != null)
            {
                object IndexedProperty = this.GetType().InvokeMember(name, invokeAttr, binder, target, null, modifiers, culture, namedParameters);
                return IndexedProperty.GetType().InvokeMember("Item", invokeAttr, binder, IndexedProperty, args, modifiers, culture, namedParameters);
            }
            // default InvokeMember
            return this.GetType().InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
        }
        catch (MissingMemberException ex)
        {
            // Well-known HRESULT returned by IDispatch.Invoke:
            const int DISP_E_MEMBERNOTFOUND = unchecked((int)0x80020003);
            throw new COMException(ex.Message, DISP_E_MEMBERNOTFOUND);
        }
    }

    FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr)
    {
        return this.GetType().GetField(name, bindingAttr);
    }

    MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr)
    {
        return this.GetType().GetMember(name, bindingAttr);
    }

    MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr)
    {
        return this.GetType().GetMembers(bindingAttr);
    }

    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr)
    {
        return this.GetType().GetMethod(name, bindingAttr);
    }

    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr,
    Binder binder, Type[] types, ParameterModifier[] modifiers)
    {
        return this.GetType().GetMethod(name, bindingAttr, binder, types, modifiers);
    }

    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr,
    Binder binder, Type returnType, Type[] types,
    ParameterModifier[] modifiers)
    {
        return this.GetType().GetProperty(name, bindingAttr, binder,
        returnType, types, modifiers);
    }

    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr)
    {
        return this.GetType().GetProperty(name, bindingAttr);
    }

    Type IReflect.UnderlyingSystemType
    {
        get { return this.GetType().UnderlyingSystemType; }
    }
}

وولرمز مايك:

[ClassInterface(ClassInterfaceType.None)]
public class TestRequest : CustomDispatch, IRequest {
    private IRequestDictionary _queryString = new RequestDictionary();

    public IRequestDictionary QueryString {
        get { return _queryString; }
    }
}

وI ديفيد بورتشر الحل يعمل بالنسبة لي.

ولكن الرمز الذي كان قد شارك التعامل مع جزء من الحصول على مفهرس، ولذا فإنني تحديث كود له للتعامل أيضا جزء من مجموعة مفهرس

وهنا هو رمز تحديث:

   // Called by CLR to invoke a member
    object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
    {
        try
        {
            // Test if it is an indexed Property - Getter
            if (name != "Item" && (invokeAttr & BindingFlags.GetProperty) == BindingFlags.GetProperty && args.Length > 0 && this.GetType().GetProperty(name) != null)
            {
                object IndexedProperty = this.GetType().InvokeMember(name, invokeAttr, binder, target, null, modifiers, culture, namedParameters);
                return IndexedProperty.GetType().InvokeMember("Item", invokeAttr, binder, IndexedProperty, args, modifiers, culture, namedParameters);
            }
            // Test if it is an indexed Property - Setter
            // args == 2 : args(0)=Position, args(1)=Vlaue
            if (name != "Item" && (invokeAttr & BindingFlags.PutDispProperty) == BindingFlags.PutDispProperty && (args.Length == 2) && this.GetType().GetProperty(name) != null)
            {
                // Get The indexer Property
                BindingFlags invokeAttr2 = BindingFlags.GetProperty;
                object IndexedProperty = this.GetType().InvokeMember(name, invokeAttr2, binder, target, null, modifiers, culture, namedParameters);

                // Invoke the Setter Property
                return IndexedProperty.GetType().InvokeMember("Item", invokeAttr, binder, IndexedProperty, args, modifiers, culture, namedParameters);
            }


            // default InvokeMember
            return this.GetType().InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
        }
        catch (MissingMemberException ex)
        {
            // Well-known HRESULT returned by IDispatch.Invoke:
            const int DISP_E_MEMBERNOTFOUND = unchecked((int)0x80020003);
            throw new COMException(ex.Message, DISP_E_MEMBERNOTFOUND);
        }
    }

والمهرج هنا ... هل قمت بفحص التجميع الخاص بك مع <لأ href = "http://www.microsoft.com/downloads/details.aspx؟familyid=5233b70d-d9b2-4cb5-aeb6-45664be858b6&displaylang=en" يختلط = "نوفولو noreferrer"> oleview للتأكد من الواجهة العمومية لديه مفهرس مرئية للمستهلكين كوم؟ المهرج الثاني هو استخدام الأسلوب get_Item مباشرة، بدلا من محاولة استخدام خاصية مفهرس (قضايا الامتثال CLS) ...

وجدت أن testRequest.QueryString()("key") يعمل ولكن ما أريده هو testRequest.QueryString("key").

لقد المادة ذات الصلة من قبل إريك ليبرت (الذي لديه حقا بعض المواد كبيرة على VBScript, بالمناسبة).هذه المادة ، VBScript الخاصية الافتراضية دلالات, يناقش شروط ما إذا كان استدعاء الخاصية الافتراضية أو مجرد استدعاء الأسلوب.قانون بلدي هو يتصرف مثل استدعاء الأسلوب على الرغم من أنه يبدو لتلبية شروط الخاصية الافتراضية.

هنا هي القواعد من اريك المادة:

القاعدة ومنفذي IDispatch::Invoke إذا كان كل من التالية صحيحا:

  • المتصل استدعاء خاصية
  • المتصل يمر حجة قائمة
  • العقار في الواقع لا تأخذ حجة قائمة
  • تلك الخاصية بإرجاع كائن
  • هذا الكائن يحتوي على الخاصية الافتراضية
  • هذه الخاصية الافتراضية يأخذ حجة قائمة

ثم استدعاء الخاصية الافتراضية مع الحجة قائمة.

يمكن لأي شخص معرفة ما إذا كان أي من هذه الشروط لم تتحقق?أو هل من الممكن أن يكون الافتراضي .صافي تنفيذ IDispatch.Invoke يتصرف بشكل مختلف ؟ أي اقتراحات ؟

ولقد قضيت بضعة أيام مع نفس المشكلة بالضبط تحاول كل شكل ممكن باستخدام أساليب متعددة. هذه الوظيفة تحل لي المشكلة:

ويلي استخدامها لتوليد خطأ parentobj.childobj (0) سبق القيام به: parentobj.childobj.item (0)

وعن طريق تغيير:

Default Public ReadOnly Property Item(ByVal key As Object) As string
    Get
        Return strSomeVal

    End Get
End Property

إلى:

Public Function Fields(Optional ByVal key As Object = Nothing) As Object

    If key Is Nothing Then
        Return New clsFieldProperties(_dtData.Columns.Count)
    Else
        Return strarray(key)
    End If
End Function

حيث:

وclsFieldProperties الفئة العامة     _intCount الخاصة وعدد صحيح

Sub New(ByVal intCount As Integer)
    _intCount = intCount

End Sub
Public ReadOnly Property Count() As Integer
    Get
        Return _intCount
    End Get
End Property

ونهاية الدرجة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top