locked
How to Update IPropertySet in MFT

    Question

  • I am working on writing an MFT that I can dynamically configure with a C# Metro Application and after picking through other similar forum posts I have managed to send information FROM the C# App to the MFT, but I cannot seem to make it work in reverse.

    My SetProperties function looks like this:

    HRESULT CAugInterface::SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
    {
         HRESULT hr = S_OK;
         pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting));
         return hr;
    }

    and the spSetting variable is declared as follows in the header file so that other parts of the MFT can access it:

    ComPtr<IMap<HSTRING, IInspectable *>> spSetting;

    I've gotten this far using information gleaned from this post: http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/f140c786-032a-4892-b502-baae0127a5cb/ and have browsed every single other post I can find on the subject. I can successfully update the PropertySet from C# and access the changes in my MFT during runtime with this code:

    WindowsCreateString(L"action", 6, &key);
    spSetting->HasKey(key, &keyExists);
    if(keyExists)
    {
         spSetting->Lookup(key, &value);
    }
    value->QueryInterface(IID_PPV_ARGS(&ref));
    ref->get_Value(&valueInt);
    if (valueInt == 1){
         // Run code for action 1
    }
    else {
         // Run code for action 2
    }

    I have tried everything I can think of but I don't quite understand IInspectable* and how to use the Insert function in the property set so that information can be passed back to my C# program.

    Any guidance would be much appreciated.

    Wednesday, September 19, 2012 6:24 PM

Answers

  • I found a solution to my problem and I wanted to outline what exactly I did so others can follow.

    This feels a little hacky to me, but it gets information from the MFT to the C# portion of the app, which is exactly what it needs to do.

    First, I implemented a custom interface that inherits from IInspectable with a single function: GetMsg. It just puts the value of a test string in the MFT into a string passed by the C#. This can obviously be changed to include parameters to change what it will pass back.

    This is what my IDL looks like:

    [version(NTDDI_WIN8), uuid(B3083C8C-E32E-416C-B02B-5DDBEBE23F74)]
    interface IGui : IInspectable {
         HRESULT GetMsg([out] HSTRING *message);
    }
    [version(NTDDI_WIN8)]
    runtimeclass AugInterface
    {
         [default] interface IGui;
    }

    Next, I had my MFT class use this custom interface and implemented the function.

    In my MFT header file:

    class CAugInterface : public Microsoft::WRL::RuntimeClass<
               Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, 
               ABI::Windows::Media::IMediaExtension,
    		   IMFTransform, ABI::AugRealityInterface::IGui>
    {
        InspectableClass(RuntimeClass_AugRealityInterface_AugInterface, BaseTrust)
    public:
        CAugInterface();
    	
        ~CAugInterface();
        IFACEMETHOD(GetMsg)(_Out_ HSTRING *message);

    I implemented the method in my cpp file (not posting because it was super simple.)

    And this is where it starts to feel 'hacky'. I had previously implemented SetProperties, and I changed this function to insert a reference to the MFT class so that the C# could get access.

    HRESULT CAugInterface::SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
    {
    	HRESULT hr = S_OK;
    	pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting));
    	HSTRING key;
    		boolean success;
    		WindowsCreateString(L"ref", 3, &key);
    		spSetting->Insert(key, static_cast<ABI::AugRealityInterface::IGui*>(this), &success);
    	return hr;
    }

    Note: The static_cast is NECESSARY and is there because of ambiguous inheritance. There may be a more gracefull way to handle this but this 'just worked'.

    And then, finally, the moment of truth. I created a variable in my C# to hold the reference to the MFT and call the GetMsg function:

    // Variable Dec (I did this at the very beginning so other parts could access it.
    AugRealityInterface.AugInterface augGui;
    // Unsafe might not be necessary. 
    //I tried a few different things and just left it in there at the end.
    unsafe void  pSet_MapChanged(IObservableMap<string, object> sender, IMapChangedEventArgs<string> @event)
            {
               if ((sender as IObservableMap<string, object>).ContainsKey("ref") && augGui == null)
                {
                    augGui = (AugRealityInterface.AugInterface)(sender as IObservableMap<string, object>)["ref"];
                }
                return;
            }
    // Then, augGui can call GetMsg like so:
    string message;
    augGui.GetMsg(out message);
    // Now message will have the test string that was passed back.

    Hopefully this helps some people -- I've been scouring the internet for the answer to these problems for weeks!

    • Marked as answer by Savallion Friday, September 21, 2012 6:32 PM
    Friday, September 21, 2012 6:32 PM

All replies

  • Hello,

    What type is "ref"?

    -James


    Windows Media SDK Technologies - Microsoft Developer Services - http://blogs.msdn.com/mediasdkstuff/

    Thursday, September 20, 2012 1:22 AM
    Moderator
  • Ah, yes.
    I also pulled that from the forum post I have linked above, it is type:

    Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IReference<int>>

    Thursday, September 20, 2012 5:26 AM
  • I found a solution to my problem and I wanted to outline what exactly I did so others can follow.

    This feels a little hacky to me, but it gets information from the MFT to the C# portion of the app, which is exactly what it needs to do.

    First, I implemented a custom interface that inherits from IInspectable with a single function: GetMsg. It just puts the value of a test string in the MFT into a string passed by the C#. This can obviously be changed to include parameters to change what it will pass back.

    This is what my IDL looks like:

    [version(NTDDI_WIN8), uuid(B3083C8C-E32E-416C-B02B-5DDBEBE23F74)]
    interface IGui : IInspectable {
         HRESULT GetMsg([out] HSTRING *message);
    }
    [version(NTDDI_WIN8)]
    runtimeclass AugInterface
    {
         [default] interface IGui;
    }

    Next, I had my MFT class use this custom interface and implemented the function.

    In my MFT header file:

    class CAugInterface : public Microsoft::WRL::RuntimeClass<
               Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, 
               ABI::Windows::Media::IMediaExtension,
    		   IMFTransform, ABI::AugRealityInterface::IGui>
    {
        InspectableClass(RuntimeClass_AugRealityInterface_AugInterface, BaseTrust)
    public:
        CAugInterface();
    	
        ~CAugInterface();
        IFACEMETHOD(GetMsg)(_Out_ HSTRING *message);

    I implemented the method in my cpp file (not posting because it was super simple.)

    And this is where it starts to feel 'hacky'. I had previously implemented SetProperties, and I changed this function to insert a reference to the MFT class so that the C# could get access.

    HRESULT CAugInterface::SetProperties(ABI::Windows::Foundation::Collections::IPropertySet *pConfiguration)
    {
    	HRESULT hr = S_OK;
    	pConfiguration->QueryInterface(IID_PPV_ARGS(&spSetting));
    	HSTRING key;
    		boolean success;
    		WindowsCreateString(L"ref", 3, &key);
    		spSetting->Insert(key, static_cast<ABI::AugRealityInterface::IGui*>(this), &success);
    	return hr;
    }

    Note: The static_cast is NECESSARY and is there because of ambiguous inheritance. There may be a more gracefull way to handle this but this 'just worked'.

    And then, finally, the moment of truth. I created a variable in my C# to hold the reference to the MFT and call the GetMsg function:

    // Variable Dec (I did this at the very beginning so other parts could access it.
    AugRealityInterface.AugInterface augGui;
    // Unsafe might not be necessary. 
    //I tried a few different things and just left it in there at the end.
    unsafe void  pSet_MapChanged(IObservableMap<string, object> sender, IMapChangedEventArgs<string> @event)
            {
               if ((sender as IObservableMap<string, object>).ContainsKey("ref") && augGui == null)
                {
                    augGui = (AugRealityInterface.AugInterface)(sender as IObservableMap<string, object>)["ref"];
                }
                return;
            }
    // Then, augGui can call GetMsg like so:
    string message;
    augGui.GetMsg(out message);
    // Now message will have the test string that was passed back.

    Hopefully this helps some people -- I've been scouring the internet for the answer to these problems for weeks!

    • Marked as answer by Savallion Friday, September 21, 2012 6:32 PM
    Friday, September 21, 2012 6:32 PM
  • Hi,

    Is there any sample for the whole codes? I don't know how to achieve AugInterface


    NEU_ShieldEdge

    Monday, May 27, 2013 1:41 PM
  • Hi, how did you hook in the pSet_MapChanged into the C# managed code?  When to connect the property settings?  I have everything else compiling but not sure where this should be hooked into the code so it is executed on the C# side.  thanks for sharing this piece. 
    Tuesday, June 11, 2013 1:27 AM
  • here is some code I wrote that demonstrates this... this uses C++ CX to construct the property set, not an issue in your use, but might be useful to see how that is done. in this sample I read a value from the property set and write one. I am using WRL, I recommend you use this too as it simplifies the code some...

    #include <windows.h>
    #include <windows.foundation.h>
    #include <windows.foundation.collections.h>
    #include <wrl.h>
    #include <wrl\wrappers\corewrappers.h>
     
    using namespace Platform;
    using namespace Platform::Details;
     
    // C++ (ABI) code that reads and populates a property set
    void TestPropSetABI(ABI::Windows::Foundation::Collections::IPropertySet *propSet)
    {
        using namespace Microsoft::WRL;
        using namespace Microsoft::WRL::Wrappers;
        using namespace ABI::Windows::Foundation;
        using namespace ABI::Windows::Foundation::Collections;
     
        ComPtr<IMap<HSTRINGIInspectable *>> map;
        propSet->QueryInterface(IID_PPV_ARGS(&map)); // IPropertySet is a IMap<> via interface requires
     
        // read a value
        ComPtr<IInspectable> valueInspectable;
        map->Lookup(HStringReference(L"Name").Get(), &valueInspectable);
        ComPtr<IPropertyValue> value;
        valueInspectable.As(&value);
        HString valueString;
        value->GetString(valueString.GetAddressOf());
     
        // using C++ CX for logging, remove for regular C++ code
        Console::WriteLine("Name = " + ref new Platform::String(valueString.Get()));
     
        // populate the value using the static property value object
        ComPtr<IPropertyValueStatics> propValueFactory;
        GetActivationFactory(
            HStringReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(),
            &propValueFactory);
        propValueFactory->CreateString(HStringReference(L"ValueFromABI").Get(), &valueInspectable);
        boolean replaced;
        map->Insert(HStringReference(L"NameFromABI").Get(), valueInspectable.Get(), &replaced);
    }
     
    // C++ CX code that creates, populates and reads a property set from CX and ABI
    void TestPropSet()
    {
        auto propSet = ref new Windows::Foundation::Collections::PropertySet();
        propSet->Insert("Name""Value");
        TestPropSetABI(reinterpret_cast<ABI::Windows::Foundation::Collections::IPropertySet *>(propSet));
        auto value = propSet->Lookup("Name");
        Console::WriteLine("Name = " + value);
        value = propSet->Lookup("NameFromABI");
        Console::WriteLine("NameFromABI = " + value);
    }
    Sunday, June 16, 2013 7:17 PM
  • Hi Chris,

    thanks for sharing the code on the C++ side.   Would you also post C# code that demonstrates the read and write operations to the MFT?  that would complete the picture here.

    Saturday, June 22, 2013 11:58 AM
  • Hi, this exactly what i'm looking for, thanks so much!

    BTW, Is this a thread-safe free solution, In the case, when MFT will update some data each frame and the Metro App consume data by using a timer then update UI, should I add some data sync mechanism?

    Wednesday, September 11, 2013 5:36 AM