如何使控件可以从c ++ builder xe2中的其他线程访问?

时间:2012-06-18 14:53:16

标签: c++ c++builder c++builder-xe2

我下载了c ++ builder xe2的试用版,我试图找出如何访问和更改控件属性(例如:从不同的线程更改TLabel的文本)。我知道您可以使用以下命令在同一个线程上更改它:

Label1->Caption = " Text ";

但我需要做的是从另一个功能改变它。到目前为止,在我的表单的头文件中:

//---------------------------------------------------------------------------

#ifndef Hello_VCLH
#define Hello_VCLH

#define IN
#define INOUT
#define OUT

//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ComCtrls.hpp>
//---------------------------------------------------------------------------
class TForm2 : public TForm
{
__published:    // IDE-managed Components
    TLabel *Label1;
    TButton *Button1;
    TProgressBar *ProgressBar1;
private:    // User declarations
public:     // User declarations
    __fastcall TForm2(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm2 *Form2;
//---------------------------------------------------------------------------
#endif

在表单的.cpp文件中,我尝试将TForm2 :: Label1-&gt; Caption =“test”;但那没用。 我尝试在控件前放置静态,但是当我这样做时,xe2声称表单代码是错误的。任何人都知道如何使它到我可以从主要的另一个功能或线程访问控件的地方?谢谢!

编辑**:

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Hello_VCL.h"
#include <tchar.h>
#include <windows.h>
#include "wimgapi.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;

//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
    : TForm(Owner)
{
}


DWORD
WINAPI
SampleCaptureCallback(
    IN      DWORD msgId,    //message ID
    IN      WPARAM param1,   //usually file name
    INOUT   LPARAM param2,   //usually error code
    IN      void  *unused
    )
{
    //First parameter: full file path for if WIM_MSG_PROCESS, message string for others
    TCHAR *message  = (TCHAR *) param1;
    TCHAR *filePath = (TCHAR *) param1;
    DWORD percent   = (DWORD)   param1;

    //Second parameter: message back to caller if WIM_MSG_PROCESS, error code for others
    DWORD errorCode = param2;
    DWORD *msg_back = (DWORD *) param2;
    DWORD seconds = (DWORD) param2;


    switch ( msgId )
    {
        case WIM_MSG_PROGRESS:

            // Prints out the current progress percentage.
            //

            //lbl->Caption="Test";

            Label1->Caption = (String)param1 + " % completed";
            //Label1->Caption = (DWORD)param1;
            //wprintf(L"__________________\n\n| Capture process|\t\t(c) 2012 Andrew Butler\n__________________\n\n%d %% captured. About %i seconds(s) remaining - %i minute(s)", (DWORD)param1, ((INT)seconds / 1000), ((INT)seconds / 60000));

            break;
        case WIM_MSG_PROCESS:

            //This message is sent for each file, capturing to see if callee intends to
            //capture the file or not.
            //
            //If you do not intend to capture this file, then assign FALSE in msg_back
            //and still return WIM_MSG_SUCCESS.
            //Default is TRUE.
            //

            //In this example, print out the file name being applied
            //
            //_tprintf(TEXT("FilePath: %s\n"), filePath);

            break;

        case WIM_MSG_ERROR:

            //This message is sent upon failure error case
            //
            //printf("ERROR: %s [err = %d]\n", message, errorCode);
            break;

        case WIM_MSG_RETRY:

            //This message is sent when the file is being reapplied because of
            //network timeout. Retry is done up to five times.
            //
            //printf("RETRY: %s [err = %d]\n", message, errorCode);
            break;

        case WIM_MSG_INFO:

            //This message is sent when informational message is available
            //
            //printf("INFO: %s [err = %d]\n", message, errorCode);
            break;

        case WIM_MSG_WARNING:

            //This message is sent when warning message is available
            //
            //printf("WARNING: %s [err = %d]\n", message, errorCode);
            break;
    }

    return WIM_MSG_SUCCESS;
}

void
SampleCaptureCleanup ( HANDLE hWim, HANDLE hImg, FARPROC callback )
{
    if (hImg) {
        WIMCloseHandle (hImg);
    }

    if (hWim) {
        WIMCloseHandle (hWim);
    }

    if (callback) {
        WIMUnregisterMessageCallback( NULL, callback );
    }
}

//---------------------------------------------------------------------------


void __fastcall TForm2::Button1Click(TObject *Sender)
{
    //Label1->Caption = "Test";
}

编辑2 *

FARPROC callback = (FARPROC) SampleCaptureCallback;

if (WIMRegisterMessageCallback( NULL,
                                callback,
                                NULL ) == INVALID_CALLBACK_VALUE) {
    printf ("Cannot set callback\n");
    return 3;
}

我已将其编辑为包含cpp文件。我想在SampleCallback函数中更改WIM_MSG_PROGRESS:的情况下的标签。

1 个答案:

答案 0 :(得分:1)

WIMRegisterMessageCallback调用的最后一个参数指定了一个自定义用户数据,可用于将信息传递给回调函数(在其最后一个参数中,当前名为unused)。

您可以通过修改注册呼叫将<{1}}对象的指针传递给回调

TForm2

其中WIMRegisterMessageCallback( NULL, callback, form) 是上面提到的指针。

然后您可以在回调中使用该用户数据,如下所示:

form

其中DWORD WINAPI SampleCaptureCallback( IN DWORD msgId, IN WPARAM param1, INOUT LPARAM param2, IN PVOID udata) { TForm2* form = reinterpret_cast<TForm2*>(udata); udata->SetLabel1Caption("my text"); //... } SetLabel1Caption的以下函数:

TForm2

其中void SetLabel1Cation(String str) { WaitForSingleObject(hLabel1Mutex, INFINITE); Label1->Caption = str; ReleaseMutex(hLabel1Mutex); } 互斥锁是hLabel1

的成员变量
Tform2

并在HANDLE hLabel1Mutex; 的构造函数中初始化为:

TForm2

注意此示例仅适用于hLabel1Mutex = CreateMutex (NULL, FALSE, NULL); if (hLabel1Mutex == NULL) { // failed to create mutex, throw exception } 。如果要同时更新多个控件,可以使用相同的互斥锁,否则应使用自己的互斥锁保护每个控件。

注意:详细了解Win32API in these articles中的互斥锁作为入门者。

更新:Remy指出传统的保护机制(互斥/信号量)不适用于完整的线程安全。相反,各种线程需要协同工作并与主线程通信,以委托对UI控件的访问。