Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do ComWrappers support proxies well? #101909

Open
Gaoyifei1011 opened this issue May 6, 2024 · 8 comments
Open

Do ComWrappers support proxies well? #101909

Gaoyifei1011 opened this issue May 6, 2024 · 8 comments
Labels
area-Interop-coreclr untriaged New issue has not been triaged by the area owner

Comments

@Gaoyifei1011
Copy link

Gaoyifei1011 commented May 6, 2024

Description

Do ComWrappers support proxies well?
ComWrappers 是否能很好的支持代理?

I tried using ComWrappers and the built-in COM support to call the deliveryoptimization.h API (deliveryoptimization) separately to try to download the file. But when using the built-in COM support, the file downloads normally, and when using ComWrappers, the download fails, returning an unknown HRESULT error code. So how do we solve this problem?
我尝试使用 ComWrappers 和内置的COM支持分别调用 deliveryoptimization.h 的 API(传递优化)尝试下载文件。但是当使用内置的COM支持时,文件可以正常下载,使用 ComWrappers 时,下载失败,返回了一个不知道是什么的HRESULT 错误代码。所以请求一下这个问题该怎么解决?

Reproduction Steps

1.创建两种API调用模板,一种是内置的COM支持下,另一种是基于ComWrappers的。
2.使用 CoCreateInstance 创建 IDoManager 的接口实例对象
3.调用 IDoManager 接口的 CreateDownload 方法创建 IDODownload 接口实例对象,创建新的下载任务。
4.获取 IDoDownload 接口对象的指针,并使用 CoSetProxyBlanket 为该接口创建代理
5.为 IDoDownload 接口对象添加下载信息
6.调用 IDoDownload 接口的 Start() 方法启动下载

  1. Create two API call templates, one with built-in COM support and one based on ComWrappers.
  2. Run CoCreateInstance to create the IDoManager interface instance object
  3. Run the CreateDownload method of the IDoManager interface to create an instance object of the IDODownload interface to create a new download task.
  4. Get a pointer to the IDoDownload interface object and create a proxy for the interface using CoSetProxyBlanket
  5. Add download information for an interface object IDoDownload
  6. Call the Start() method of the IDoDownload interface to start the download

Expected behavior

基于 ComWrappers 调用 Start 方法返回的结果为 0,表示成功创建下载
A call to the Start method based on ComWrappers returns 0, indicating that the download was successfully created

Actual behavior

基于内置支持的接口返回的HRESULT 错误代码为 0,表示下载任务成功启动。基于 ComWrappers 的返回的 HRESULT 错误代码为 0x80D02018,不知道对应的是什么错误信息
If HRESULT error code 0 is returned based on the built-in supported interface, the download task is successfully started. The HRESULT error code returned by ComWrappers is 0x80D02018. What is the corresponding error message

Regression?

None

Known Workarounds

If you want to successfully create the download task, you must convert to built-in COM support, but this does not work well with Native AOT
如果想成功创建下载任务,必须转换为内置的 COM 支持,但是这样就不能很好的兼容 Native AOT

Configuration

.NET Version: .NET 9 preview3
OS version: Windows 11 22635.3570
Architecture:X64

Other information

Screenshot of code error based on ComWrappers launch download task
基于 ComWrappers 启动下载任务错误的代码截图
image

Screenshot of code for successfully starting download tasks based on built-in COM support
基于内置的COM支持成功启动下载任务的代码截图
image

Test source code
测试源代码
DeliveryOptimizationTest.zip

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label May 6, 2024
@huoyaoyuan
Copy link
Member

Trying your example, it fails at this line:

doDownload.SetProperty(DODownloadProperty.DODownloadProperty_LocalPath, &filePathVarient);

The return HRESULT is 0x80010123 (CO_E_FAILEDTOIMPERSONATE).
I also noticed E_INVALIDARG in you built-in COM sample.

@Gaoyifei1011
Copy link
Author

Gaoyifei1011 commented May 6, 2024

Trying your example, it fails at this line:

doDownload.SetProperty(DODownloadProperty.DODownloadProperty_LocalPath, &filePathVarient);

The return HRESULT is 0x80010123 (CO_E_FAILEDTOIMPERSONATE). I also noticed E_INVALIDARG in you built-in COM sample.

Built-in COM
image

ComWrappers
image

Thank you for your check, I noticed this problem. When I tested it on my side, it only appeared in ComWrappers, build-in COM didn't happen
感谢您的检查,我注意到了这一个问题。我这边测试的时候,只在ComWrappers中出现,Built-in COM并未发生

所以我很想知道,我的代码是写的发生了bug,还是 ComWrappers 对 proxy 的支持有问题?
如果我的代码发生了bug,希望社区里的大佬能对其进行纠正,非常感谢(目前对它的修改已经超出了我的能力范围,很抱歉)。
So I wonder, is my code written in a bug, or is ComWrappers' support for the proxy a problem?
If there is a bug in my code, I hope the community leaders can correct it, thank you very much (the current modification of it is beyond my ability, I'm sorry).

@huoyaoyuan
Copy link
Member

Though I'm not familiar with ComWrappers, there are multiple interop-related issues or suggestions in your code:

SetProperty and GetProperty should define their parameters as in ComVariant and out ComVariant and you don't need to create the temporary variables.
new UnknownWrapper(doDownloadStatusCallback).WrappedObject is a nop, just use the original object.
Embedded reference types in struct (DO_DOWNLOAD_RANGE[] and string) are not friendly for marshalling. Use singular DO_DOWNLOAD_RANGE, InlineArray, and raw char* instead.

I'm not sure what can be "proxy" releated here. The CoSetProxyBlanket is a plain P/Invoke with blittable arguments, and returns without error.

@Gaoyifei1011
Copy link
Author

Though I'm not familiar with ComWrappers, there are multiple interop-related issues or suggestions in your code:

SetProperty and GetProperty should define their parameters as in ComVariant and out ComVariant and you don't need to create the temporary variables. new UnknownWrapper(doDownloadStatusCallback).WrappedObject is a nop, just use the original object. Embedded reference types in struct (DO_DOWNLOAD_RANGE[] and string) are not friendly for marshalling. Use singular DO_DOWNLOAD_RANGE, InlineArray, and raw char* instead.

I'm not sure what can be "proxy" releated here. The CoSetProxyBlanket is a plain P/Invoke with blittable arguments, and returns without error.

Though I'm not familiar with ComWrappers, there are multiple interop-related issues or suggestions in your code:

SetProperty and GetProperty should define their parameters as in ComVariant and out ComVariant and you don't need to create the temporary variables. new UnknownWrapper(doDownloadStatusCallback).WrappedObject is a nop, just use the original object. Embedded reference types in struct (DO_DOWNLOAD_RANGE[] and string) are not friendly for marshalling. Use singular DO_DOWNLOAD_RANGE, InlineArray, and raw char* instead.

I'm not sure what can be "proxy" releated here. The CoSetProxyBlanket is a plain P/Invoke with blittable arguments, and returns without error.

For your 1,3 suggestions, you can try to modify the code I provided, you can check if it supports com source generation
The second suggestion, you can view the DotNet runtime rawcode about Marshal.GetObjectForNativeVariant method

@huoyaoyuan
Copy link
Member

huoyaoyuan commented May 6, 2024

you can check if it supports com source generation

They are not supported at all. Trying to use them on com interface causes error.

you can view the DotNet runtime rawcode

It's before reaching any method. new UnknownWrapper(obj).WrappedObject just populates the object passed into constructor back.

@Gaoyifei1011
Copy link
Author

you can check if it supports com source generation

They are not supported at all. Trying to use them on com interface causes error.

you can view the DotNet runtime rawcode

It's before reaching any method. new UnknownWrapper(obj).WrappedObject just populates the object passed into constructor back.

So that's the real reason for it, and it requires us to make some adjustments to the code.

@huoyaoyuan
Copy link
Member

I'm referring to this code in your project:

IntPtr callbackPointer = comWrappers.GetOrCreateComInterfaceForObject(new UnknownWrapper(doDownloadStatusCallback).WrappedObject, CreateComInterfaceFlags.None);

You aren't passing the UnknownWrapper object at all.

@hez2010
Copy link
Contributor

hez2010 commented May 7, 2024

It seems that the authentication information did not being set correctly on the proxy object by CoSetProxyBlanket.

Related to #101157, cc: @AaronRobinsonMSFT does it ring any bells?

As a workaround, you can try calling CoInitializeSecurity before you instantiating CLSID_DeliveryOptimization to set the default security values for the process instead:

CoInitializeSecurity(0, -1, 0, 0, 0, 3, 0, 0x20, 0);

[LibraryImport(Ole32), PreserveSig]
static partial int CoInitializeSecurity(nint pSecDesc, nint cAuthSvc, nint asAuthSvc, nint pReserved1, int dwAuthnLevel, int dwImpLevel, nint pAuthList, int dwCapabilities, nint pReserved3);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Interop-coreclr untriaged New issue has not been triaged by the area owner
Projects
None yet
Development

No branches or pull requests

3 participants