| name | review-case |
| description | Code review for API examples. Ensures examples follow project conventions, handle lifecycle correctly, manage threads safely, and use APIs properly.
|
| compatibility | ["Cursor","Kiro","Windsurf","Claude","Copilot"] |
| license | MIT |
| metadata | {"author":"APIExample Team","version":"1.0.0","platform":"Windows"} |
Review Case Skill — Windows
When to Use
Use this skill when you need to:
- Review a new or modified example for correctness
- Ensure the example follows project conventions
- Verify lifecycle management and thread safety
- Check API usage and error handling
Review Dimensions (Priority Order)
1. Engine Lifecycle (CRITICAL)
Check:
Correct Pattern A — standalone dialog teardown:
BOOL CExampleDlg::OnInitDialog() {
CDialogEx::OnInitDialog();
InitializeAgoraEngine();
return TRUE;
}
void CExampleDlg::PostNcDestroy() {
LeaveChannel();
if (m_rtcEngine) {
m_rtcEngine->release();
m_rtcEngine = nullptr;
}
CDialogEx::PostNcDestroy();
delete this;
}
void CExampleDlg::JoinChannel() {
if (!m_rtcEngine) return;
m_rtcEngine->joinChannel(token, channelName, "", 0);
}
void CExampleDlg::LeaveChannel() {
if (!m_rtcEngine) return;
m_rtcEngine->leaveChannel();
}
Correct Pattern B — scene-switching dialog teardown:
bool CExampleDlg::InitAgora() {
m_rtcEngine = createAgoraRtcEngine();
return m_rtcEngine != nullptr;
}
void CExampleDlg::UnInitAgora() {
if (!m_rtcEngine) return;
if (m_joinChannel) {
m_rtcEngine->leaveChannel();
}
m_rtcEngine->release(nullptr);
m_rtcEngine = nullptr;
}
void CExampleDlg::OnShowWindow(BOOL bShow, UINT nStatus) {
CDialogEx::OnShowWindow(bShow, nStatus);
if (!bShow) {
UnInitAgora();
}
}
Accept either pattern as long as the dialog follows one lifecycle consistently and does not leak the engine across scene switches.
Incorrect Pattern:
See references/incorrect-lifecycle.cpp for common mistakes.
2. Thread Safety (CRITICAL)
Check:
Correct Pattern:
void CExampleRtcEngineEventHandler::onJoinChannelSuccess(const char* channel, uid_t uid, int elapsed) {
if (m_hMsgHandler) {
::PostMessage(m_hMsgHandler, WM_MSGID(EID_JOIN_CHANNEL_SUCCESS), (WPARAM)uid, 0);
}
}
LRESULT CExampleDlg::OnMsgEngineEvent(WPARAM wParam, LPARAM lParam) {
m_statusText.SetWindowText(_T("Joined channel"));
return 0;
}
Incorrect Pattern:
See references/incorrect-thread-safety.cpp for common mistakes.
3. Permission Handling (HIGH)
Check:
Correct Pattern:
void CExampleDlg::InitializeAgoraEngine() {
m_rtcEngine = createAgoraRtcEngine();
if (!m_rtcEngine) return;
RtcEngineContext context;
context.appId = CConfig::GetAppId();
context.eventHandler = &m_eventHandler;
m_eventHandler.SetMsgReceiver(m_hWnd);
m_rtcEngine->initialize(context);
if (m_rtcEngine->enableVideo() == 0) {
}
if (m_rtcEngine->enableAudio() == 0) {
}
}
4. Error Handling (HIGH)
Check:
Correct Pattern:
void CExampleDlg::JoinChannel() {
if (!m_rtcEngine) return;
const char* token = CConfig::GetToken("test");
int ret = m_rtcEngine->joinChannel(token, "test", "", 0);
if (ret != 0) {
MessageBox(_T("Failed to join channel"), _T("Error"));
}
}
void CExampleRtcEngineEventHandler::onError(int err) {
if (m_hMsgHandler) {
::PostMessage(m_hMsgHandler, WM_MSGID(EID_ERROR), (WPARAM)err, 0);
}
}
LRESULT CExampleDlg::OnMsgEngineEvent(WPARAM wParam, LPARAM lParam) {
if (wParam == EID_ERROR) {
int errorCode = (int)lParam;
}
return 0;
}
5. Code Convention (MEDIUM)
Check:
Correct Pattern:
class CScreenShareRtcEngineEventHandler : public IRtcEngineEventHandler {
};
class CScreenShareDlg : public CDialogEx {
DECLARE_DYNAMIC(CScreenShareDlg)
private:
IRtcEngine* m_rtcEngine = nullptr;
CScreenShareRtcEngineEventHandler m_eventHandler;
uid_t m_remoteUid = 0;
bool m_isJoined = false;
BEGIN_MESSAGE_MAP(CScreenShareDlg, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON_JOIN, &CScreenShareDlg::OnBnClickedButtonJoin)
END_MESSAGE_MAP()
};
6. API Usage Correctness (MEDIUM)
Check:
Correct Pattern:
m_rtcEngine = createAgoraRtcEngine();
m_rtcEngine->initialize(context);
m_rtcEngine->enableVideo();
m_rtcEngine->enableAudio();
m_rtcEngine->joinChannel(token, channelName, "", 0);
Incorrect Pattern:
m_rtcEngine->joinChannel(...);
m_rtcEngine->enableVideo();
7. Resource Cleanup (MEDIUM)
Check:
Correct Pattern:
void CExampleDlg::LeaveChannel() {
if (!m_rtcEngine) return;
m_rtcEngine->stopAudioMixing();
m_rtcEngine->stopScreenCapture();
m_rtcEngine->leaveChannel();
m_isJoined = false;
}
void CExampleDlg::PostNcDestroy() {
LeaveChannel();
if (m_rtcEngine) {
m_rtcEngine->release();
m_rtcEngine = nullptr;
}
CDialogEx::PostNcDestroy();
delete this;
}
Review Output Format
When reviewing, provide feedback in this format:
## Review Results
### ✅ Passed
- Engine lifecycle correctly managed
- Thread safety ensured with message map pattern
- Error handling implemented for joinChannel
### ⚠️ Issues Found
**[HIGH] Thread Safety Issue**
- File: `CScreenShareDlg.cpp`
- Line: 45
- Issue: Direct UI update in event handler without PostMessage
- Suggestion: Use PostMessage to post event to main thread
**[MEDIUM] Missing Error Handling**
- File: `CScreenShareDlg.cpp`
- Line: 78
- Issue: joinChannel() return value not checked
- Suggestion: Check return value and handle errors
### 🔧 Recommendations
- Add logging for debugging
- Consider adding retry logic for network failures
Platform-Specific Checks
Windows-Specific
Check:
Correct Pattern:
#include "stdafx.h"
#include "APIExample.h"
class CExampleDlg : public CDialogEx {
DECLARE_DYNAMIC(CExampleDlg)
BEGIN_MESSAGE_MAP(CExampleDlg, CDialogEx)
ON_BN_CLICKED(IDC_BUTTON_JOIN, &CExampleDlg::OnBnClickedButtonJoin)
END_MESSAGE_MAP()
};
Incorrect Pattern:
using namespace std;
auto ptr = std::make_unique<IRtcEngine>();
NEVER List
Do NOT accept:
- Engine not released (memory leak)
- Direct UI updates from event handler without PostMessage
- Multiple engine instances in one example
- Hardcoded App ID or token (must use CConfig)
- Missing
leaveChannel() before release()
- C# or other languages (C++ only)
- WinForms or WPF (MFC only)
- Examples outside
APIExample/APIExample/[Basic|Advanced]/ structure
- Missing event handler implementation
- No error handling for joinChannel failures
- Deviation from MFC naming conventions
Review Checklist
Use this checklist when reviewing an example:
Lifecycle:
Thread Safety:
Permissions:
Error Handling:
Code Quality:
API Usage:
Resources:
Platform:
Common Issues and Fixes
Issue: "Engine not initialized"
Cause: release() called without leaveChannel() first
Fix: Always call leaveChannel() before release()
Issue: "UI crashes or doesn't update"
Cause: Direct UI update from event handler
Fix: Use PostMessage to post event to main thread
Issue: "Memory leak detected"
Cause: release() not called or engine recreated
Fix: Ensure release() in PostNcDestroy() and create engine once
Issue: "Token expired error"
Cause: No token refresh handling
Fix: Implement token refresh in error handler
Issue: "No audio/video"
Cause: Device not available or not enabled
Fix: Check return values of enableAudio() / enableVideo()
References