File: C:/Users/fred/.codex/.tmp/plugins/plugins/zoom/skills/meeting-sdk/windows/examples/chat.md
# Meeting Chat - Send and Receive Messages
## Overview
The Meeting SDK provides a rich chat API through `IMeetingChatController`. You can:
- Send messages to all participants or specific users
- Receive incoming chat messages
- Apply rich text formatting (bold, italic, links, colors)
- Handle file transfers
- Support threaded conversations
## Architecture
```
IMeetingService
└── GetMeetingChatController() → IMeetingChatController
├── SetEvent(IMeetingChatCtrlEvent*)
├── GetChatMessageBuilder() → IChatMsgInfoBuilder
├── SendChatMsgTo(IChatMsgInfo*)
└── GetChatStatus()
```
## Required Headers
```cpp
#include <meeting_service_interface.h>
#include <meeting_service_components/meeting_chat_interface.h>
```
## Step 1: Implement the Chat Event Listener
```cpp
// MeetingChatEventListener.h
#pragma once
#include <meeting_service_components/meeting_chat_interface.h>
class MeetingChatEventListener : public ZOOMSDK::IMeetingChatCtrlEvent {
public:
MeetingChatEventListener() = default;
virtual ~MeetingChatEventListener() = default;
// Called when a new chat message arrives
virtual void onChatMsgNotification(
ZOOMSDK::IChatMsgInfo* chatMsg,
const zchar_t* content
) override;
// Called when chat privileges change
virtual void onChatStatusChangedNotification(
ZOOMSDK::ChatStatus* status
) override;
// Called when a message is deleted
virtual void onChatMsgDeleteNotification(
const zchar_t* msgID,
ZOOMSDK::SDKChatMessageDeleteType deleteBy
) override;
// Called when a message is edited
virtual void onChatMessageEditNotification(
ZOOMSDK::IChatMsgInfo* chatMsg
) override;
// Called when meeting chat sharing status changes
virtual void onShareMeetingChatStatusChanged(bool isStart) override;
// File transfer callbacks
virtual void onFileSendStart(ZOOMSDK::ISDKFileSender* sender) override;
virtual void onFileReceived(ZOOMSDK::ISDKFileReceiver* receiver) override;
virtual void onFileTransferProgress(ZOOMSDK::SDKFileTransferInfo* info) override;
};
```
```cpp
// MeetingChatEventListener.cpp
#include "MeetingChatEventListener.h"
#include <iostream>
using namespace ZOOMSDK;
void MeetingChatEventListener::onChatMsgNotification(
IChatMsgInfo* chatMsg,
const zchar_t* content
) {
if (chatMsg && content) {
// Get sender information
unsigned int senderId = chatMsg->GetSenderUserId();
const zchar_t* senderName = chatMsg->GetSenderDisplayName();
// Get message details
const zchar_t* msgContent = chatMsg->GetContent();
SDKChatMessageType msgType = chatMsg->GetChatMessageType();
std::wcout << L"[Chat] " << senderName << L": " << msgContent << std::endl;
// Check message type
switch (msgType) {
case SDKChatMessageType_To_All:
std::cout << " (sent to everyone)" << std::endl;
break;
case SDKChatMessageType_To_Individual:
std::cout << " (private message)" << std::endl;
break;
case SDKChatMessageType_To_WaitingRoomUsers:
std::cout << " (to waiting room)" << std::endl;
break;
}
// Check if this is a threaded reply
const zchar_t* threadId = chatMsg->GetThreadID();
if (threadId && wcslen(threadId) > 0) {
std::wcout << L" Thread ID: " << threadId << std::endl;
}
}
}
void MeetingChatEventListener::onChatStatusChangedNotification(ChatStatus* status) {
if (status) {
std::cout << "Chat status changed" << std::endl;
// Check what chat privileges are available
}
}
void MeetingChatEventListener::onChatMsgDeleteNotification(
const zchar_t* msgID,
SDKChatMessageDeleteType deleteBy
) {
std::wcout << L"Message deleted: " << msgID << std::endl;
switch (deleteBy) {
case SDKChatMessageDeleteType_By_Self:
std::cout << " (deleted by sender)" << std::endl;
break;
case SDKChatMessageDeleteType_By_Host:
std::cout << " (deleted by host)" << std::endl;
break;
case SDKChatMessageDeleteType_By_DLP:
std::cout << " (deleted by DLP policy)" << std::endl;
break;
}
}
void MeetingChatEventListener::onChatMessageEditNotification(IChatMsgInfo* chatMsg) {
if (chatMsg) {
std::wcout << L"Message edited: " << chatMsg->GetContent() << std::endl;
}
}
void MeetingChatEventListener::onShareMeetingChatStatusChanged(bool isStart) {
std::cout << "Share meeting chat: " << (isStart ? "started" : "stopped") << std::endl;
}
void MeetingChatEventListener::onFileSendStart(ISDKFileSender* sender) {
std::cout << "File send started" << std::endl;
}
void MeetingChatEventListener::onFileReceived(ISDKFileReceiver* receiver) {
std::cout << "File received" << std::endl;
}
void MeetingChatEventListener::onFileTransferProgress(SDKFileTransferInfo* info) {
// Handle file transfer progress
}
```
## Step 2: Initialize Chat Controller
```cpp
// Global variables
IMeetingChatController* g_chatController = nullptr;
MeetingChatEventListener* g_chatListener = nullptr;
void initializeChat(IMeetingService* meetingService) {
// Get the chat controller
g_chatController = meetingService->GetMeetingChatController();
if (!g_chatController) {
std::cerr << "Failed to get chat controller" << std::endl;
return;
}
// Create and set event listener
g_chatListener = new MeetingChatEventListener();
SDKError err = g_chatController->SetEvent(g_chatListener);
if (err != SDKERR_SUCCESS) {
std::cerr << "Failed to set chat event listener: " << err << std::endl;
return;
}
std::cout << "Chat controller initialized" << std::endl;
}
```
## Step 3: Send Chat Messages
### Simple Text Message (To Everyone)
```cpp
void sendMessageToAll(const wchar_t* message) {
if (!g_chatController) return;
// Get the message builder
IChatMsgInfoBuilder* builder = g_chatController->GetChatMessageBuilder();
if (!builder) {
std::cerr << "Failed to get message builder" << std::endl;
return;
}
// Build the message
builder->SetContent(message);
builder->SetReceiver(0); // 0 = everyone
builder->SetMessageType(SDKChatMessageType_To_All);
// Build and send
IChatMsgInfo* msgInfo = builder->Build();
if (msgInfo) {
SDKError err = g_chatController->SendChatMsgTo(msgInfo);
if (err == SDKERR_SUCCESS) {
std::cout << "Message sent successfully" << std::endl;
} else {
std::cerr << "Failed to send message: " << err << std::endl;
}
}
}
```
### Private Message (To Specific User)
```cpp
void sendPrivateMessage(unsigned int userId, const wchar_t* message) {
if (!g_chatController) return;
IChatMsgInfoBuilder* builder = g_chatController->GetChatMessageBuilder();
if (!builder) return;
builder->SetContent(message);
builder->SetReceiver(userId); // Specific user ID
builder->SetMessageType(SDKChatMessageType_To_Individual);
IChatMsgInfo* msgInfo = builder->Build();
if (msgInfo) {
SDKError err = g_chatController->SendChatMsgTo(msgInfo);
if (err == SDKERR_SUCCESS) {
std::cout << "Private message sent" << std::endl;
}
}
}
```
### Rich Text Message with Formatting
```cpp
void sendFormattedMessage() {
if (!g_chatController) return;
IChatMsgInfoBuilder* builder = g_chatController->GetChatMessageBuilder();
if (!builder) return;
// Set content: "Hello, this is BOLD and this is italic"
const wchar_t* content = L"Hello, this is BOLD and this is italic";
builder->SetContent(content);
builder->SetReceiver(0);
builder->SetMessageType(SDKChatMessageType_To_All);
// Apply bold to "BOLD" (positions 14-17, 0-indexed)
builder->SetBold(14, 18);
// Apply italic to "italic" (positions 32-37)
builder->SetItalic(32, 38);
// Build and send
IChatMsgInfo* msgInfo = builder->Build();
if (msgInfo) {
g_chatController->SendChatMsgTo(msgInfo);
}
}
```
### Message with Link
```cpp
void sendMessageWithLink() {
if (!g_chatController) return;
IChatMsgInfoBuilder* builder = g_chatController->GetChatMessageBuilder();
if (!builder) return;
// Set content with link text
const wchar_t* content = L"Check out this website for more info";
builder->SetContent(content);
builder->SetReceiver(0);
builder->SetMessageType(SDKChatMessageType_To_All);
// Create link attributes
InsertLinkAttrs linkAttrs;
linkAttrs.insertLinkUrl = L"https://zoom.us";
// Apply link to "this website" (positions 10-21)
builder->SetInsertLink(linkAttrs, 10, 22);
IChatMsgInfo* msgInfo = builder->Build();
if (msgInfo) {
g_chatController->SendChatMsgTo(msgInfo);
}
}
```
### Threaded Reply
```cpp
void sendThreadedReply(const wchar_t* threadId, const wchar_t* message) {
if (!g_chatController) return;
IChatMsgInfoBuilder* builder = g_chatController->GetChatMessageBuilder();
if (!builder) return;
builder->SetContent(message);
builder->SetReceiver(0);
builder->SetMessageType(SDKChatMessageType_To_All);
builder->SetThreadId(threadId); // Reply to existing thread
IChatMsgInfo* msgInfo = builder->Build();
if (msgInfo) {
g_chatController->SendChatMsgTo(msgInfo);
}
}
```
## Complete Integration Example
```cpp
void onInMeeting(IMeetingService* meetingService) {
// Initialize chat when in meeting
initializeChat(meetingService);
// Send a greeting
sendMessageToAll(L"Hello everyone! Bot has joined the meeting.");
}
// Call from your meeting status callback
void MeetingServiceEventListener::onMeetingStatusChanged(
MeetingStatus status,
int iResult
) {
if (status == MEETING_STATUS_INMEETING) {
onInMeeting(g_meetingService);
}
}
```
## IChatMsgInfoBuilder Methods Reference
| Method | Description |
|--------|-------------|
| `SetContent(const zchar_t*)` | Set message text content |
| `SetReceiver(unsigned int)` | Set recipient (0 = everyone) |
| `SetMessageType(SDKChatMessageType)` | Set message type (all, individual, waiting room) |
| `SetThreadId(const zchar_t*)` | Set thread ID for replies |
| `SetBold(start, end)` | Apply bold style |
| `SetItalic(start, end)` | Apply italic style |
| `SetUnderline(start, end)` | Apply underline style |
| `SetStrikethrough(start, end)` | Apply strikethrough style |
| `SetFontColor(FontColorAttrs, start, end)` | Set font color |
| `SetBackgroundColor(BackgroundColorAttrs, start, end)` | Set background color |
| `SetFontSize(FontSizeAttrs, start, end)` | Set font size |
| `SetInsertLink(InsertLinkAttrs, start, end)` | Insert hyperlink |
| `SetBulletedList(start, end)` | Apply bulleted list style |
| `SetNumberedList(start, end)` | Apply numbered list style |
| `SetQuotePosition(start, end)` | Apply quote style |
| `SetParagraph(ParagraphAttrs, start, end)` | Set paragraph style (H1, H2, H3) |
| `ClearStyles()` | Clear all styles |
| `Clear()` | Clear all properties |
| `Build()` | Build the IChatMsgInfo object |
## Chat Message Types
```cpp
enum SDKChatMessageType {
SDKChatMessageType_To_None, // Invalid
SDKChatMessageType_To_All, // To everyone
SDKChatMessageType_To_Individual, // Private message
SDKChatMessageType_To_Individual_Panelist, // Webinar panelist
SDKChatMessageType_To_WaitingRoomUsers // To waiting room
};
```
## Error Handling
```cpp
SDKError err = g_chatController->SendChatMsgTo(msgInfo);
switch (err) {
case SDKERR_SUCCESS:
std::cout << "Message sent" << std::endl;
break;
case SDKERR_INVALID_PARAMETER:
std::cerr << "Invalid message parameters" << std::endl;
break;
case SDKERR_NO_PERMISSION:
std::cerr << "No permission to send chat" << std::endl;
break;
case SDKERR_WRONG_USAGE:
std::cerr << "Chat not available (not in meeting?)" << std::endl;
break;
default:
std::cerr << "Failed to send: " << err << std::endl;
}
```
## Common Pitfalls
1. **Chat controller unavailable**: Must be in a meeting (`MEETING_STATUS_INMEETING`)
2. **Position indexing**: Style positions are 0-indexed and use character positions, not byte positions
3. **Unicode support**: Use `wchar_t*` and `std::wstring` for proper Unicode support
4. **Builder reuse**: The builder can be reused, but call `Clear()` between messages
5. **Thread ID**: When replying to a thread, get the thread ID from `IChatMsgInfo::GetThreadID()`