0

C++ ビルダー 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ファイルを含めるように編集しました。SampleCallback 関数の WIM_MSG_PROGRESS: の下のラベルを変更したいと考えています。

4

1 に答える 1

1

呼び出しの最後のパラメーターは、WIMRegisterMessageCallbackコールバック関数に情報を渡すために使用できるカスタム ユーザー データを指定します (最後のパラメーターで、現在は という名前が付けられています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);
}

ここで、hLabel1mutex はメンバー変数ですTform2

HANDLE hLabel1Mutex;

のコンストラクタで次のように初期TForm2化されます。

hLabel1Mutex = CreateMutex (NULL, FALSE, NULL);
if (hLabel1Mutex == NULL)
{
  // failed to create mutex, throw exception
}

この例は、 のみを使用するように調整されていることに注意Label1してください。同時に複数のコントロールを更新する場合は、同じミューテックスを使用できます。それ以外の場合は、各コントロールを独自のミューテックスで保護する必要があります。

: Win32API のミューテックスの詳細については これらの 記事をスターターとしてお読みください。

更新: Remy は、従来の保護メカニズム (ミューテックス/セマフォ) は、ここでは完全なスレッド セーフには適用できないと指摘しています。代わりに、さまざまなスレッドが連携してメイン スレッドと通信し、UI コントロールへのアクセスを委任する必要があります。

于 2012-06-18T16:00:02.553 に答える