본문 바로가기
놀기/Qt

QT에서 SendMessage() 사용하기

by Hi~ 2023. 9. 9.

MFC를 사용하던 시절 SendMessage()를 자주 사용했다. 운영체제에서 보내주는 메시지를 받을 수 있고 다른 프로그램의 핸들을 얻어 메시지를 전달할 수도 있었다. MFC는 Windows를 만든 M$에서 만들었기에 친Windows 라고 할 수 있는데 QT에서도 SendMessage()를 사용하고 운영체제가 보내주는 메시지를 받을 수 있다. 앞서 올린 USB 저장장치 꺼내기에서도 사용한 QT의 nativeEvent()와 SendMessage()를 추후에 사용할 목적으로 따로 정리한다.

 

2023.09.05 - [놀기/Qt] - USB 저장장치 꺼내기 (How to eject an external drive or USB stick)

 

USB 저장장치 꺼내기 (How to eject an external drive or USB stick)

USB 저장 장치에 파일을 복사하는 프로그램을 만드는데 이왕이면 꺼내기까지 기능까지 같이 넣으면 좋겠다는 생각이 들었다. 일반적인 프로그램에서 되니 OS에서 지원하는 API가 있다는 것이니

busyman.tistory.com

 

 

 

여기서는 WM_COPYDATA와 WM_USER를 사용해보려한다. 정답은 아니고 이런 식으로 사용 가능하구나 정도로 읽어 주시길... 전체 소스코드는 게시물 아래에서 다운로드.

 

1) nativeEvent() 추가하기

nativeEvent()를 사용하기 위해서는 헤더에 아래와 같이 추가하고 소스파일에 해당 함수의 구현부를 작성하면 된다. nativeEvent()에서 메시지를 받으면 처리하는 방식인데 코드를 보면 익숙한 방식일 듯하다. 메시지를 받는 방식은 이렇게만 하면 된다.

// mainwindow.h
class MainWindow : public QMainWindow
{
    Q_OBJECT

	// 중략
public:
	bool nativeEvent(const QByteArray &type, void *vMsg, long *result);
    
    
	// 중략
};


// mainwindow.cpp
bool MainWindow::nativeEvent(const QByteArray &type, void *vMsg, long *result)
{
    Q_UNUSED(type);
    MSG *msg = (MSG*)vMsg;

    if (msg->message == WM_USER)
    {
        if ((0x0B == msg->wParam) && (0xB0 == msg->lParam)) {
            ui->teRecvMessage->append(QString("WM_USER: wParam(0x%1), lParam(0x%2)").arg(msg->wParam, 2, 16, QLatin1Char('0')).arg(msg->lParam, 2, 16, QLatin1Char('0')));
        }
    }
    else if (msg->message == WM_COPYDATA) {
        PCOPYDATASTRUCT pcds = reinterpret_cast<PCOPYDATASTRUCT>(msg->lParam);
        QByteArray* data = (QByteArray *)pcds->lpData;
        ui->teRecvMessage->append(QString("WM_COPYDATA: data(%1)").arg(data->constData()));
    }

    // end of if msg->message
    *result = 0; //get rid of obnoxious compiler warning

    return false; // let qt handle the rest
}

 

 

2) SendMessage() 사용하기

이 메시지를 사용하기 위해서는 Handle을 얻어야 한다. QT에서는 다음과 같은 방식으로 할 수 있다.

 

먼저, main.cpp의 내용을 아래와 같이 변경해야 한다.

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

#if 0
    MainWindow w;
    w.show();
    return a.exec();
#else
    MainWindow* mainwindow = MainWindow::getInstance();
    mainwindow->show();
    return a.exec();
#endif
}

 

그리고, getInstance()를 MainWindow에 만든다.

// mainwindow.cpp

MainWindow* MainWindow::instance = NULL;


// mainwindow.h
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    static MainWindow* getInstance() {
        // !NOT thread safe  - first call from main only
        if (!instance)
            instance = new MainWindow();
        return instance;
    }

    bool nativeEvent(const QByteArray &type, void *vMsg, long *result);

private slots:
    void slotSendMessage1();
    void slotSendMessage2();

private:
    Ui::MainWindow *ui;
    static MainWindow* instance;
};

 

위와 같이 한 후에 아래와 같이 Handle을 얻을 수 있다.

HWND h = (HWND) MainWindow::getInstance()->winId();

 

그럼 이제 준비가 되었다. SendMessage() 호출은 우리(?)가 아는 방식으로 하면 된다.

 

// WM_COPYDATA 예시
void MainWindow::slotSendMessage1()
{
    HWND h = (HWND) MainWindow::getInstance()->winId();

    QByteArray data;
    QString s = ui->leMessage->text();
    data += s;

    COPYDATASTRUCT cds{};
    cds.dwData = 1;
    cds.lpData = (PVOID) &data;
    cds.cbData = strlen((char*)cds.lpData);

    SendMessage(h, WM_COPYDATA, (WPARAM)0x00, (LPARAM)&cds);
}

// WM_USER 예시
void MainWindow::slotSendMessage2()
{
    HWND h = (HWND) MainWindow::getInstance()->winId();
    SendMessage(h, WM_USER, 0x0B, 0xB0);
}

 

실행하면 아래와 같이 된다.

 

소스코드가 구리고 지저분하지만 필요한 분은 다운로드 ㅎㅎ

 

bmSendMessageTest-master.zip
0.01MB

 

 

댓글