2016-04-14 63 views
1

我尝试使用Win32函数QueueUserWorkItem()作为工作项来调用私有成员函数(不应该作为公共或受保护的方式提供)。我知道我以前做过这件事,而且很容易,但是现在我找不到那个片段,也不能让bind()伏都教工作。因此,对于这个问题的目的,类是:使用私有成员函数调用Win32 QueueUserWorkItem()

class Arbitrary { 

    public: 
     Arbitrary() ; 
     ~Arbitrary() ; 

     bool UsefulPublicFunction(unsigned uParameter) ; 

    protected: 

    private: 
     void PrivateWorkItem(void* pVoid) ; 
} ; 

而且里面UsefulPublicFunction()我们可能会看到:

LPTHREAD_START_ROUTINE pThreadStartRoutine ; 
ULONG uFlags = 0 ; 
void* pContext = nullptr ; 

if (QueueUserWorkItem(pThreadStartRoutine, pContext, uFlags)) { 
    //blah blah blah 
} 

在哪里我好像在杂草熄灭是分配给pThreadStartRoutine喜欢的东西:

pThreadStartRoutine = std::bind<&Arbitrary::PrivateWorkItem, this, std::placeholders::_1> ; 

我认识到,PrivateWorkItem签名或许应该改为:

private: 
    DWORD WINAPI PrivateWorkItem(void* pVoid) ; 

即使有了这样的变化,也没有快乐。 VS2015真的很讨厌我使用bind()的方式。

我应该为pThreadStartRoutine分配什么样的内容?

+0

这将有助于了解你所看到的错误。 –

+0

错误消息被请求...对我来说这是没用的 - 也许它对你有意义: “没有重载函数的实例”std :: bind“匹配所需的类型” – BenWestbrook

回答

0

这似乎工作:

#include <Windows.h> 

#include <stdio.h> 

#include <functional> 

using namespace std::placeholders; 

class Arbitrary { 

    public: 

     bool UsefulPublicFunction(int uParameter); 

    protected: 

    private: 
     typedef std::function<void (void)> CallbackType; 
     static DWORD WINAPI ProcessWorkItem(void* pVoid); 
     void PrivateWorkItem1(int arg1, int arg2); 
     void PrivateWorkItem2(char * arg1); 
}; 

void Arbitrary::PrivateWorkItem1(int arg1, int arg2) 
{ 
    printf("Numbers are %u %u\n", arg1, arg2); 
    return; 
} 

void Arbitrary::PrivateWorkItem2(char * arg1) 
{ 
    printf("String is %s\n", arg1); 
    return; 
} 

DWORD WINAPI Arbitrary::ProcessWorkItem(void* pVoid) 
{ 
    CallbackType * callback = static_cast<CallbackType *>(pVoid); 
    (*callback)(); 
    delete callback; 
    return 0; 
} 

bool Arbitrary::UsefulPublicFunction(int param1) 
{ 
    QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem1, this, param1, 7)), 0); 

    QueueUserWorkItem(&ProcessWorkItem, new CallbackType(std::bind(&Arbitrary::PrivateWorkItem2, this, (char *)"This is my string")), 0); 

    Sleep(1000); 
    return true; 
} 

int main(int argc, char ** argv) 
{ 
    Arbitrary x; 

    x.UsefulPublicFunction(5); 

    return 0; 
} 
+0

太棒了!谢谢。 – BenWestbrook

+0

对不起,我还没有足够的分数来冲击哈利的“得分”。 – BenWestbrook

1

尝试一些更喜欢这个:

class Arbitrary { 

    public: 
     Arbitrary() ; 
     ~Arbitrary() ; 

     bool UsefulPublicFunction(unsigned uParameter); 

    protected: 

    private: 
     static DWORD WINAPI PrivateWorkItem(void* pVoid) ; 
     void PrivateFunction(); 
} ; 

DWORD WINAPI Arbitrary::PrivateWorkItem(void* pVoid) 
{ 
    static_cast<Arbitrary*>(pVoid)->PrivateFunction(); 
    return 0; 
} 

... 

if (QueueUserWorkItem(&PrivateWorkItem, this, 0)) { 
    //blah blah blah 
} 
+0

这“感觉”相当笨拙,并且从长远的代码维护角度来看,我似乎没有那么可靠 - 主要是因为班上实际存在许多独特的私人工作者职能。但是,是的,我按照你的建议来完成它,而且我还用正确的签名声明和自动变量,然后用memcpy将它猛击到pThreadStartRoutine中,但对我来说这看起来很笨拙。 关于这一点,使用绑定似乎直截了当,当实习生在10年内维护此代码时的意图。 – BenWestbrook

+0

您无法真正使用'std :: bind()'来设置Win32 API回调函数(请参阅http://stackoverflow.com/questions/18161680/)。我上面展示的是“最干净”的解决方案,不涉及丑陋的黑客。 –

+0

你大概会使用一个静态函数,它接受一个指向由std :: bind生成的转发调用包装的指针。只要调用封装来自C++而不是Windows。 –