Как сделать элементы управления доступными из других потоков в 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->Caption = " test"; но это не сработало. Я попытался поместить static перед элементами управления, но когда я это делаю, 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. Я хочу изменить метку в случае WIM_MSG_PROGRESS: в функции SampleCallback.

1 ответ

Решение

Последний параметр WIMRegisterMessageCallback call определяет пользовательские пользовательские данные, которые вы можете использовать для передачи информации в вашу функцию обратного вызова unused).

Вы можете передать указатель на ваш 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
}

Обратите внимание, что этот пример предназначен только для использования Label1, Если вы хотите обновить более одного элемента управления одновременно, вы можете использовать один и тот же мьютекс, иначе вы должны защитить каждый элемент управления своим собственным мьютексом.

Примечание. Подробнее о мьютексах в Win32API см. В этих статьях для начинающих.

Обновление: Реми отмечает, что традиционные механизмы защиты (мьютекс / семафор) здесь не применимы для полной безопасности потока. Вместо этого различные потоки должны работать вместе и взаимодействовать с основным потоком, чтобы делегировать доступ к элементам управления пользовательского интерфейса.

Другие вопросы по тегам