C
C#2y ago
Chen Chen

❔ ✅ A question for the device of Surface Dial development.

I want to test the codes for surface dail from https://learn.microsoft.com/en-us/windows/apps/design/input/radialcontroller-walkthrough. The difference is that I want to use a console, while the sample codes use a window and buttons. The picture shows the error when run my codes. The error is "System.Exception: "The application invoked an interface that was marshaled for another thread." How could I debug this problem. Or are there some advice for my coding? thank you!
15 Replies
reflectronic
reflectronic2y ago
so, when you use UWP APIs, you need to be careful about APIs with "CreateForCurrentView" or similar in the name they only work in a UWP app, because it only know how to find the "current view" for a UWP app. you are writing a console app, so that does not work many of these APIs have an alternative but it requires some extra code:
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;

// https://learn.microsoft.com/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerinterop
[ComImport]
[Guid("1B0535C9-57AD-45C1-9D79-AD5C34360513")]
[InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
interface IRadialControllerInterop
{
object CreateForWindow(IntPtr hwnd, in Guid refiid);
}

public void InitializeController()
{
[DllImport("kernel32")]
static extern IntPtr GetConsoleWindow();

IntPtr hwnd = GetConsoleWindow();

IRadialControllerInterop interop = (IRadialControllerInterop)WindowsRuntimeMarshal.GetActivationFactory(typeof(RadialController));
Guid iid = typeof(RadialController).GetInterface("IRadialController").GUID;
radialController = (RadialController)interop.CreateForWindow(hwnd, iid);
}
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;

// https://learn.microsoft.com/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerinterop
[ComImport]
[Guid("1B0535C9-57AD-45C1-9D79-AD5C34360513")]
[InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
interface IRadialControllerInterop
{
object CreateForWindow(IntPtr hwnd, in Guid refiid);
}

public void InitializeController()
{
[DllImport("kernel32")]
static extern IntPtr GetConsoleWindow();

IntPtr hwnd = GetConsoleWindow();

IRadialControllerInterop interop = (IRadialControllerInterop)WindowsRuntimeMarshal.GetActivationFactory(typeof(RadialController));
Guid iid = typeof(RadialController).GetInterface("IRadialController").GUID;
radialController = (RadialController)interop.CreateForWindow(hwnd, iid);
}
if you need a RadialControllerConfiguration, it is a similar trick:
// https://learn.microsoft.com/en-us/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerconfigurationinterop
[ComImport]
[Guid("787CDAAC-3186-476D-87E4-B9374A7B9970")]
[InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
interface IRadialControllerConfigurationInterop
{
object GetForWindow(IntPtr hwnd, in Guid riid);
}

public void InitializeController()
{
IRadialControllerConfigurationInterop interop = (IRadialControllerConfigurationInterop)WindowsRuntimeMarshal.GetActivationFactory(typeof(RadialControllerConfiguration));
Guid iid = typeof(RadialControllerConfiguration).GetInterface("IRadialControllerConfiguration").GUID;
radialControllerConfiguration = (RadialControllerConfiguration)interop.CreateForWindow(hwnd, iid);
}
// https://learn.microsoft.com/en-us/windows/win32/api/radialcontrollerinterop/nn-radialcontrollerinterop-iradialcontrollerconfigurationinterop
[ComImport]
[Guid("787CDAAC-3186-476D-87E4-B9374A7B9970")]
[InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
interface IRadialControllerConfigurationInterop
{
object GetForWindow(IntPtr hwnd, in Guid riid);
}

public void InitializeController()
{
IRadialControllerConfigurationInterop interop = (IRadialControllerConfigurationInterop)WindowsRuntimeMarshal.GetActivationFactory(typeof(RadialControllerConfiguration));
Guid iid = typeof(RadialControllerConfiguration).GetInterface("IRadialControllerConfiguration").GUID;
radialControllerConfiguration = (RadialControllerConfiguration)interop.CreateForWindow(hwnd, iid);
}
after you have created these objects, there should be no more special code required, it should be pretty straightforward. if it still doesn't work, i would guess that it has something to do with this being a console app (you might need a Windows message loop). in this case, it would be simpler to make a windows forms app to try this in the code would be the same, except of course instead of using GetConsoleWindow you would use myForm.Handle to tell RadialController which window your actions are supposed to be associated with
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Chen Chen
Chen ChenOP2y ago
/close Thank you! I will learn and try. Thank you again! I tried your solution, using a sample from https://github.com/Microsoft/Windows-classic-samples/tree/main/Samples/RadialController/cs/winforms.
reflectronic
reflectronic2y ago
it's not neccessary for RadialControllerMenuItem
Chen Chen
Chen ChenOP2y ago
I add a method, but it note work. So, is it that this method is not available for RadialControllerMenuItem? How should I do if I want to do some thing when the added menu item is invoked? Thank you !
Chen Chen
Chen ChenOP2y ago
It seems that the Invoke method is banded to radialControllerMenuItem.
reflectronic
reflectronic2y ago
right. that event should just work apart from creating those two objects--RadialController and RadialControllerConfiguration--everything is the same as UWP
Chen Chen
Chen ChenOP2y ago
Sorry, I do not understand. It seems that I can not do things when a menu item is selected. For example, I want to run different actions if I add two additional menu items, and they represent different following actions. If the RadialControllerMenuItem can not be get as the RadialController and RadialControllerConfiguration, how should I use the Invoked method?
reflectronic
reflectronic2y ago
you make the RadialControllerMenuItem by using RadialControllerMenuItem.CreateFromIcon, or one of the other static methods that let you create one there is no "special" way to create them, it is just the normal way and you use Invoked like the sample code does to run your code when the button is clicked
Chen Chen
Chen ChenOP2y ago
Thank you! I will try. It seems that the RadialControllerMenuItem is not banded to a handle, so it is not need to use the extra codes. Is it right?
reflectronic
reflectronic2y ago
right, it does not have the "GetForCurrentView" API which does not work in WinForms. that is what the interop code is working around
Chen Chen
Chen ChenOP2y ago
Ok! I see. Thank you !
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Chen Chen
Chen ChenOP2y ago
!close
Accord
Accord2y ago
Closed! Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server