Qutlook 예제 (ActiveQt)

Qutlook 예제는 ActiveQt를 사용하여 Outlook을 자동화하는 방법을 보여줍니다. 이 예제는 dumpcpp 도구를 활용하여 Outlook 객체 모델을 설명하는 타입 라이브러리에 대한 C++ 네임스페이스를 생성합니다.

이 예제의 프로젝트 파일은 다음과 같습니다:

TEMPLATE = app
TARGET   = qutlook
QT += widgets axcontainer

TYPELIBS = $$system(dumpcpp -getfile {00062FFF-0000-0000-C000-000000000046})

isEmpty(TYPELIBS) {
    message("Microsoft Outlook type library not found!")
    REQUIRES += Outlook
} else {
    HEADERS  = addressview.h
    SOURCES  = addressview.cpp main.cpp
}

이 프로젝트 파일은 dumpcpp 도구를 사용하여 MS Outlook 타입 라이브러리를 프로젝트에 추가합니다. 이 과정이 실패하면 생성된 makefile이 오류 메시지만 출력하고, 그렇지 않은 경우 빌드 단계에서 타입 라이브러리에 대해 dumpcpp 도구를 실행하여 Outlook 객체에 대한 사용하기 쉬운 API를 선언하고 구현하는 헤더 파일과 cpp 파일(이 경우 msoutl.h 및 msoutl.cpp)을 생성합니다.

class AddressView : public QWidget
{
    Q_OBJECT

public:
    explicit AddressView(QWidget *parent = nullptr);

protected slots:
    void addEntry();
    void changeEntry();
    void itemSelected(const QModelIndex &index);

    void updateOutlook();

protected:
    AddressBookModel *model;

    QTreeView *m_treeView;
    QPushButton *m_addButton;
    QPushButton *m_changeButton;
    QLineEdit *m_firstName;
    QLineEdit *m_lastName;
    QLineEdit *m_address;
    QLineEdit *m_email;
};

AddressView 클래스는 사용자 인터페이스를 위한 QWidget 의 서브클래스입니다. QTreeView 위젯은 model 에서 제공하는 Outlook의 '연락처' 폴더 내용을 표시합니다.

#include "addressview.h"
#include "msoutl.h"
#include <QtWidgets>

class AddressBookModel : public QAbstractListModel
{
public:
    explicit AddressBookModel(AddressView *parent);
    virtual ~AddressBookModel();

    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    QVariant data(const QModelIndex &index, int role) const;

    void changeItem(const QModelIndex &index, const QString &firstName, const QString &lastName, const QString &address, const QString &email);
    void addItem(const QString &firstName, const QString &lastName, const QString &address, const QString &email);
    void update();

private:
    Outlook::Application outlook;
    Outlook::Items *folderItems = nullptr;

    mutable QHash<QModelIndex, QStringList> cache;
};

AddressBookModel 클래스는 QHash 을 캐싱에 활용하며 Outlook과 직접 통신하는 QAbstractListModel 의 하위 클래스입니다.

AddressBookModel::AddressBookModel(AddressView *parent)
: QAbstractListModel(parent)
{
    if (!outlook.isNull()) {
        Outlook::NameSpace session(outlook.Session());
        session.Logon();
        Outlook::MAPIFolder *folder = session.GetDefaultFolder(Outlook::olFolderContacts);
        folderItems = new Outlook::Items(folder->Items());
        connect(folderItems, SIGNAL(ItemAdd(IDispatch*)), parent, SLOT(updateOutlook()));
        connect(folderItems, SIGNAL(ItemChange(IDispatch*)), parent, SLOT(updateOutlook()));
        connect(folderItems, SIGNAL(ItemRemove()), parent, SLOT(updateOutlook()));

        delete folder;
    }
}

생성자는 Outlook을 초기화합니다. 콘텐츠 변경을 알리기 위해 Outlook이 제공하는 다양한 신호는 updateOutlook() 슬롯에 연결됩니다.

AddressBookModel::~AddressBookModel()
{
    delete folderItems;

    if (!outlook.isNull())
        Outlook::NameSpace(outlook.Session()).Logoff();
}

소멸자는 세션에서 로그아웃합니다.

int AddressBookModel::rowCount(const QModelIndex &) const
{
    return folderItems ? folderItems->Count() : 0;
}

int AddressBookModel::columnCount(const QModelIndex & /*parent*/) const
{
    return 4;
}

rowCount() 구현체는 Outlook에서 보고한 항목 수를 반환합니다. 트리 뷰에 4개의 열을 표시하기 위해 columnCount 및 headerData 가 구현되었습니다.

QVariant AddressBookModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    switch (section) {
    case 0:
        return tr("First Name");
    case 1:
        return tr("Last Name");
    case 2:
        return tr("Address");
    case 3:
        return tr("Email");
    default:
        break;
    }

    return QVariant();
}

headerData() 구현은 하드코딩된 문자열을 반환합니다.

QVariant AddressBookModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || role != Qt::DisplayRole)
        return QVariant();

    QStringList data;
    if (cache.contains(index)) {
        data = cache.value(index);
    } else {
        Outlook::ContactItem contact(folderItems->Item(index.row() + 1));

        if (contact.Class() == Outlook::OlObjectClass::olContact)
            data << contact.FirstName() << contact.LastName() << contact.HomeAddress() << contact.Email1Address();

        cache.insert(index, data);
    }

    if (index.column() < data.size())
        return data.at(index.column());

    return QVariant();
}

data() 구현은 모델의 핵심입니다. 요청된 데이터가 캐시에 있으면 캐시된 값이 사용되며, 그렇지 않은 경우 Outlook에서 데이터를 가져옵니다.

void AddressBookModel::changeItem(const QModelIndex &index, const QString &firstName, const QString &lastName, const QString &address, const QString &email)
{
    Outlook::ContactItem item(folderItems->Item(index.row() + 1));

    if (item.Class() != Outlook::OlObjectClass::olContact)
        return; // Not a contact

    item.SetFirstName(firstName);
    item.SetLastName(lastName);
    item.SetHomeAddress(address);
    item.SetEmail1Address(email);

    item.Save();

    cache.take(index);
}

changeItem() 슬롯은 사용자가 사용자 인터페이스를 통해 현재 항목을 변경할 때 호출됩니다. Outlook 항목을 Outlook API를 통해 액세스하고, 속성 설정자를 사용하여 수정합니다. 마지막으로, 항목을 Outlook에 저장하고 캐시에서 제거합니다. Outlook이 자체적으로 신호를 발생시키므로, 모델은 데이터 변경에 대해 뷰에 신호를 보내지 않는다는 점에 유의하십시오.

void AddressBookModel::addItem(const QString &firstName, const QString &lastName, const QString &address, const QString &email)
{
    Outlook::ContactItem item(outlook.CreateItem(Outlook::olContactItem));
    if (!item.isNull()) {
        item.SetFirstName(firstName);
        item.SetLastName(lastName);
        item.SetHomeAddress(address);
        item.SetEmail1Address(email);

        item.Save();
    }
}

addItem() 슬롯은 Outlook의 CreateItem 메서드를 호출하여 새 연락처 항목을 생성하고, 새 항목의 속성을 사용자가 입력한 값으로 설정한 후 항목을 저장합니다.

void AddressBookModel::update()
{
    beginResetModel();
    cache.clear();
    endResetModel();
}

update() 슬롯은 캐시를 지우고, reset() 신호를 발생시켜 뷰에 데이터 변경 사항을 알림으로써 내용을 다시 그려야 함을 알립니다.

AddressView::AddressView(QWidget *parent)
: QWidget(parent)
{
    QGridLayout *mainGrid = new QGridLayout(this);

    QLabel *firstNameLabel = new QLabel(tr("First &Name"), this);
    firstNameLabel->resize(firstNameLabel->sizeHint());
    mainGrid->addWidget(firstNameLabel, 0, 0);

    QLabel *lastNameLabel = new QLabel(tr("&Last Name"), this);
    lastNameLabel->resize(lastNameLabel->sizeHint());
    mainGrid->addWidget(lastNameLabel, 0, 1);

    QLabel *addressLabel = new QLabel(tr("Add&ress"), this);
    addressLabel->resize(addressLabel->sizeHint());
    mainGrid->addWidget(addressLabel, 0, 2);

    QLabel *emailLabel = new QLabel(tr("&E-Mail"), this);
    emailLabel->resize(emailLabel->sizeHint());
    mainGrid->addWidget(emailLabel, 0, 3);

    m_addButton = new QPushButton(tr("A&dd"), this);
    m_addButton->resize(m_addButton->sizeHint());
    mainGrid->addWidget(m_addButton, 0, 4);
    connect(m_addButton, &QPushButton::clicked, this, &AddressView::addEntry);

    m_firstName = new QLineEdit(this);
    m_firstName->resize(m_firstName->sizeHint());
    mainGrid->addWidget(m_firstName, 1, 0);
    firstNameLabel->setBuddy(m_firstName);

    m_lastName = new QLineEdit(this);
    m_lastName->resize(m_lastName->sizeHint());
    mainGrid->addWidget(m_lastName, 1, 1);
    lastNameLabel->setBuddy(m_lastName);

    m_address = new QLineEdit(this);
    m_address->resize(m_address->sizeHint());
    mainGrid->addWidget(m_address, 1, 2);
    addressLabel->setBuddy(m_address);

    m_email = new QLineEdit(this);
    m_email->resize(m_email->sizeHint());
    mainGrid->addWidget(m_email, 1, 3);
    emailLabel->setBuddy(m_email);

    m_changeButton = new QPushButton(tr("&Change"), this);
    m_changeButton->resize(m_changeButton->sizeHint());
    mainGrid->addWidget(m_changeButton, 1, 4);
    connect(m_changeButton, &QPushButton::clicked, this, &AddressView::changeEntry);

    m_treeView = new QTreeView(this);
    m_treeView->setSelectionMode(QTreeView::SingleSelection);
    m_treeView->setRootIsDecorated(false);

    model = new AddressBookModel(this);
    m_treeView->setModel(model);

    connect(m_treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &AddressView::itemSelected);

    mainGrid->addWidget(m_treeView, 2, 0, 1, 5);
}

void AddressView::updateOutlook()
{
    model->update();
}

void AddressView::addEntry()
{
    if (!m_firstName->text().isEmpty() || !m_lastName->text().isEmpty() ||
         !m_address->text().isEmpty() || !m_email->text().isEmpty()) {
        model->addItem(m_firstName->text(), m_lastName->text(), m_address->text(), m_email->text());
    }

    m_firstName->clear();
    m_lastName->clear();
    m_address->clear();
    m_email->clear();
}

void AddressView::changeEntry()
{
    QModelIndex current = m_treeView->currentIndex();

    if (current.isValid())
        model->changeItem(current, m_firstName->text(), m_lastName->text(), m_address->text(), m_email->text());
}

void AddressView::itemSelected(const QModelIndex &index)
{
    if (!index.isValid())
        return;

    QAbstractItemModel *model = m_treeView->model();
    m_firstName->setText(model->data(model->index(index.row(), 0)).toString());
    m_lastName->setText(model->data(model->index(index.row(), 1)).toString());
    m_address->setText(model->data(model->index(index.row(), 2)).toString());
    m_email->setText(model->data(model->index(index.row(), 3)).toString());
}

파일의 나머지 부분은 Qt API만을 사용하여, 즉 Outlook과 직접 통신하지 않고 사용자 인터페이스를 구현합니다.

#include "addressview.h"
#include <QApplication>

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

    AddressView view;
    view.setWindowTitle(QObject::tr("Qt Example - Looking at Outlook"));
    view.show();

    return a.exec();
}

main() 엔트리 포인트 함수는 최종적으로 사용자 인터페이스를 인스턴스화하고 이벤트 루프로 진입합니다.

이 예제를 빌드하려면 먼저 QAxContainer 라이브러리를 빌드해야 합니다. 그런 다음 examples/activeqt/qutlook 에서 make 도구를 실행하고, 생성된 qutlook.exe 파일을 실행하십시오.

코드.qt.io의 예제 프로젝트

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.