如何使用C#BackgroundWorker在本机C+中报告进度+;密码? 在VisualStudio解决方案中,我在C语言中实现了UI,并在原生C++中实现了一些代码。

如何使用C#BackgroundWorker在本机C+中报告进度+;密码? 在VisualStudio解决方案中,我在C语言中实现了UI,并在原生C++中实现了一些代码。,c#,c++,visual-c++,interop,C#,C++,Visual C++,Interop,我习惯于执行长操作的进度报告 < >我如何使用后台工作程序>代码来报告我的本地C++代码的进度?< /p> P> >我如何将下面的C代码改写为本机C++,并调用C语言获得的C++代码? 如果无法直接重写下面的代码,最好了解其他等效解决方案。谢谢 class MyClass { public void Calculate(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as

我习惯于执行长操作的进度报告

< >我如何使用<代码>后台工作程序>代码来报告我的本地C++代码的进度?< /p> P> >我如何将下面的C代码改写为本机C++,并调用C语言获得的C++代码? 如果无法直接重写下面的代码,最好了解其他等效解决方案。谢谢

class MyClass 
{
    public void Calculate(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        for (int i = 0; i < StepCount; i++)
        {
            if (worker.CancellationPending)
            {
                e.Cancel = true;
                break;
            }

            // code which handles current iteration here

            worker.ReportProgress((i + 1) * 100 / StepCount, 
                "Report progress message");
        }
    }
}
class-MyClass
{
公共无效计算(对象发送方,DoWorkEventArgs e)
{
BackgroundWorker worker=发件人作为BackgroundWorker;
对于(int i=0;i
在C代码中,用DLIMLIPT属性声明您的本机C++方法,并从您的代码>后台工作人员调用此方法。

免责声明:我没有测试过任何代码,这可能不是最好的方法,但至少在理论上我认为这是可行的。希望这里有一位更有经验的成员能够验证这一点是否正确

这假设您正在从C#启动后台工作程序,并且希望在C#中更改
ProgressChanged
事件(我假设是这样的,因为您的UI在C#中)

您仍然可以在C#中使用
BackgroundWorker
,但只需让它使用上面提到的dlliport调用您的本地方法即可。您还可以修改方法的签名,以获取与
ReportProgress
的签名匹配的函数指针,然后从本机代码调用该委托

MSDN上有一些文章(尽管示例都使用C++/CLI)。您可能还想查看和属性以及枚举的文档

例如,如果您的本机方法是

void foo(int arg1, BOOL arg2)
{
  // Your code here
}
您可以在本机代码中将函数指针类型定义为

// Corresponds to void BackgroundWorker.ReportProgress(int progress, object state)
typedef void (*NativeReportProgress) (int, void*);
并将您的本地签名更改为

void foo(int arg1, BOOL arg2, NativeReportProgress progressPtr)
{
  // Some code.
  progressPtr(progressValue, stateVar);
}
对于
foo
,您的
DLLImport
如下所示

// Delegate type for BackgroundWorker.ReportProgress
delegate void ReportProgressDelegate(int progress, object state);

// The MarshalAs attribute should handle the conversion from the .NET
// delegate to a native C/C++ function pointer.
[DLLImport]
void foo([MarshalAs(UnmanagedType.I4)] Int32 arg1, 
         [MarshalAs(UnmanagedType.Bool)] bool arg2, 
         [MarshalAs(UnmanagedType.FunctionPointer)] ReportProgressDelegate progressDel);
void DoWork(object sender, DoWorkEventArgs e)
{
  var worker = (BackgroundWorker)sender;
  // Notice that worker.ReportProgress is not followed the by ().
  // We're not actually calling the method here, we're just passing
  // a function pointer to that method into foo.
  foo(intArg, boolArg, worker.ReportProgress);
}
那么你的工人看起来像

// Delegate type for BackgroundWorker.ReportProgress
delegate void ReportProgressDelegate(int progress, object state);

// The MarshalAs attribute should handle the conversion from the .NET
// delegate to a native C/C++ function pointer.
[DLLImport]
void foo([MarshalAs(UnmanagedType.I4)] Int32 arg1, 
         [MarshalAs(UnmanagedType.Bool)] bool arg2, 
         [MarshalAs(UnmanagedType.FunctionPointer)] ReportProgressDelegate progressDel);
void DoWork(object sender, DoWorkEventArgs e)
{
  var worker = (BackgroundWorker)sender;
  // Notice that worker.ReportProgress is not followed the by ().
  // We're not actually calling the method here, we're just passing
  // a function pointer to that method into foo.
  foo(intArg, boolArg, worker.ReportProgress);
}
希望这是有意义的(也希望它是正确的!)

下面是一个例子。 它在x86 C#和本机Visual C++上进行了测试:

CppLayer.h:

    #ifdef CPPLAYER_EXPORTS
    #define CPPLAYER_API __declspec(dllexport)
    #else
    #define CPPLAYER_API __declspec(dllimport)
    #endif

    extern "C" {
        typedef void (__stdcall *ReportProgressCallback)(int, char *);
        typedef bool (__stdcall *CancellationPendingCallback)();

        struct CPPLAYER_API WorkProgressInteropNegotiator 
        {
            ReportProgressCallback progressCallback;
            CancellationPendingCallback cancellationPending;
            bool cancel;
        };

        CPPLAYER_API void __stdcall CppLongFunction(WorkProgressInteropNegotiator& negotiator);
    }
CppLayer.cpp:

#include "stdafx.h"
#include "CppLayer.h"

#include <iostream>

extern "C"
{
    // This is an example of an exported function.
    CPPLAYER_API void __stdcall CppLongFunction(WorkProgressInteropNegotiator& negotiator)
    {
        const int STEP_COUNT = 12;

        char * messages[3] = {"ONE", "TWO", "THREE"};

        for (int i = 0; i < STEP_COUNT; i++)
        {
            Sleep(100);

            if (negotiator.cancellationPending()) {
                negotiator.cancel = true; 
                break;
            }

            std::cout << "Calculate " << i << std::endl;
            negotiator.progressCallback((i + 1) * 100 / STEP_COUNT, messages[i % 3]);
        }
    }

};
以下链接可能有用:


这只是一个抽象概念:鉴于BackgroundWorker只是一个单独的线程,您可以在调用c#时声明一个不安全的代码段;衍生出一条新的线索;并声明一个返回报告进度的函数指针。简言之,您必须在线程和委托的抽象之下进行编程。编写本机代码的意义是什么?您使用托管对象,因此在托管代码中编写它是很自然的。如果你想在C++中写这样的东西,那么你需要本地人。code@Even首先,你的评论与问题无关。但无论如何。在C++中,UI更方便,计算密集型代码在C++中,我甚至不说当你没有选择的情况下,因为你没有启动项目,你只是有一个代码。当你有C++和C代码时,你可能需要它们之间的一些通信——在我的情况下,我需要报告进度。我的坏,我误解了这些问题。我想你是想把C++的进展报告给你的C++代码。我还没有做很多C++互操作,但我想我有一个想法。我会回复你的。我已经编辑了我的答案,我认为这是一个更正确的方法。你的答案对我来说很有用。我终于想出了现成的代码。你可以在我的回答中看一下。谢谢