# License Error using Custom UI Feature in Windows SDK

**URL:** <https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480>\
**Category:** Windows\
**Created:** [March 26, 2022, 10:17am UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480 "2022-03-26T10:17:53Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [March 26, 2022, 10:17am UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/1 "2022-03-26T10:17:53Z")

</div>

**Description**  
Trying to use custom UI feature in Windows SDK, however uiManager-\>HasLicense() returns SDKERR\_NO\_PERMISSION after it is created. The same code without custom ui will join meeting successfully.

**Which Windows Meeting SDK version?**  
zoom-sdk-windows-5.7.6.1081

**To Reproduce(If applicable)**  
This function is called on `ZOOM_SDK_NAMESPACE::MEETING_STATUS_CONNECTING` in `onMeetingStatusChanged` in my event handler class implementing `ZOOM_SDK_NAMESPACE::IMeetingServiceEvent`. I get SDKERR\_NO\_PERMISSION. If I remove the call to `customUIInit`, I can join meeting successfully. Note I’m initialising with `initParam.obConfigOpts.optionalFeatures = (1 << 5);`.

```auto
void customUIInit() {
    ZOOM_SDK_NAMESPACE::SDKError err;
    printf("Setting up custom UI handling\n");
    CustomUIEventHandler customUIEventHandler;
    ZOOM_SDK_NAMESPACE::ICustomizedUIMgr *uiManager;
    err = ZOOM_SDK_NAMESPACE::CreateCustomizedUIMgr(&uiManager);
    uiManager->SetEvent(&customUIEventHandler);
    printf("Custom UI handling result %d\n",err);

    // Check license allows
    err = uiManager->HasLicense();
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("License failure for custom UI handling - %d\n",err);
        // Getting 12 = SDKERR_NO_PERMISSION - shouldn't need a license but seems to be required :(
        printLastZoomError();
        exit(-1);
    }
...

```

**Device (please complete the following information):**  
Windows 10

**Additional context**  
Logs available, not sure how to attach?

---

<div class="post-metadata">

**Author:** ![jon.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/jon.zoom/32/13495_2.png) [@jon.zoom](https://devforum.zoom.us/u/jon.zoom)\
**Post date:** [March 28, 2022, 7:45pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/2 "2022-03-28T19:45:54Z")

</div>

Hi @max_dev, thanks for using the dev forum.

This function used to be required a long time ago when custom UI mode was not enabled for all accounts, but now all developer accounts should be able to use a custom meeting UI. You should not need to check this value before trying to join a meeting. We will work on updating our documentation to reflect this.

Thanks!

---

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [April 2, 2022, 9:29am UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/3 "2022-04-02T09:29:00Z")

</div>

Thanks @jon.zoom - ok, so if I skip the license check, when I attempt to create the video container, I get `SDKERR_UNINITIALIZE` (see code snippet below). I’ve tried to follow all the instructions on [Custom UI Feature](https://marketplace.zoom.us/docs/sdk/native-sdks/windows/mastering-sdk/custom-ui-feature/) but must be missing something.

Again, when I remove my custom UI handling, I can successfully join the meeting. Also note I’m building on mingw in windows.

Also, I note that that the license check is included in the `demo_sdk_v2` under at `custom_ui_mgr.cpp:486` - so I still think that maybe my license check should succeed?

```auto
    ZOOM_SDK_NAMESPACE::ICustomizedVideoContainer* videoContainer = NULL;
    err = uiManager->CreateVideoContainer(&videoContainer, hParent, rc);
    if (videoContainer == NULL) {
        // We hit this condition, err is 7 = SDKERR_UNINITIALIZE
        printf("Video container null on CreateVideoContainer: %d\n",err);
        printLastZoomError();
        exit(-1);
    }

```

---

<div class="post-metadata">

**Author:** ![jon.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/jon.zoom/32/13495_2.png) [@jon.zoom](https://devforum.zoom.us/u/jon.zoom)\
**Post date:** [April 4, 2022, 7:46pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/4 "2022-04-04T19:46:13Z")

</div>

Hi @max_dev,

This error indicates that you have not yet [initialized the SDK](https://marketplace.zoom.us/docs/sdk/native-sdks/windows/mastering-sdk/windows-sdk-functions#initialization). Before you can do anything with the SDK, you must first initialize it via `ZOOM_SDK_NAMESPACE::InitSDK`, and then authorize the SDK with your developer credentials via [`SDKAuth`](https://marketplacefront.zoom.us/sdk/meeting/windows/class_i_auth_service.html#a84f75bbae54ee07669cfd12ddd659783)

Thanks!

---

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [April 9, 2022, 7:59am UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/5 "2022-04-09T07:59:33Z")

</div>

Thanks @jon.zoom - the SDK is initialised and authorised as far as I can tell. The code below which runs successfully - I get `ZOOM_SDK_NAMESPACE::AUTHRET_SUCCESS` in the `onAuthenticationReturn` function in my `ZOOM_SDK_NAMESPACE::IAuthServiceEvent` implementation. If I remove the custom UI handling code, I can successfully join the meeting.

```auto
    ZOOM_SDK_NAMESPACE::InitParam initParam;
    initParam.strWebDomain = L"https://zoom.us";
    initParam.strSupportUrl = L"https://zoom.us";
    // Request Custom UI feature - see https://marketplace.zoom.us/docs/sdk/native-sdks/windows/mastering-sdk/custom-ui-feature/
    initParam.obConfigOpts.optionalFeatures = (1 << 5); 
    initParam.enableLogByDefault = true;
    //initParam.enableGenerateDump = true;
    ZOOM_SDK_NAMESPACE::SDKError err = ZOOM_SDK_NAMESPACE::InitSDK(initParam);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("failed InitSDK\n");
        printLastZoomError();
        return -1; 
    }   

    ZOOM_SDK_NAMESPACE::IAuthService *authService;
    err = ZOOM_SDK_NAMESPACE::CreateAuthService(&authService);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("failed CreateAuthService\n");
        printLastZoomError();
        return -1;
    }
    authService->SetEvent(&zoomServiceEventHandler);
    // Auth using key and secret
    ZOOM_SDK_NAMESPACE::AuthParam authParam;
    authParam.appKey = appKey.c_str();
    authParam.appSecret = appSecret.c_str();
    err = authService->SDKAuth(authParam); // AUTHRET_KEYORSECRETWRONG

    // Do the auth
    if(ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("Failed SDKAuth\n");
        printLastZoomError();
        return -1;
    }

```

---

<div class="post-metadata">

**Author:** ![jon.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/jon.zoom/32/13495_2.png) [@jon.zoom](https://devforum.zoom.us/u/jon.zoom)\
**Post date:** [April 11, 2022, 6:26pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/6 "2022-04-11T18:26:22Z")

</div>

Hi @max_dev,

Just to make sure I’m understanding correctly, can you clarify which “custom UI handling code” being removed results in you being able to successfully join the meeting?

Thanks!

---

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [April 18, 2022, 9:01am UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/7 "2022-04-18T09:01:41Z")

</div>

Hi @jon.zoom ,

So, I can:

- remove the call to `customUIInit` from my `onMeetingStatusChanged` implementation,
- remove the initialisation line `initParam.obConfigOpts.optionalFeatures = (1 << 5);`

Then I can join the meeting successfully`Preformatted text`. Here’s sample code for reference. Note that I’m using mingw on windows 10.

Thanks,

Max

**Output With Custom UI Handling**

```auto
Starting app
Args 4
Meeting number #########
App key #########
App secret #########
Waiting for event
onAuthenticationReturn - 0
onAuthenticationReturn - AUTHRET_SUCCESS
Finished waiting for event
Creating Meeting Service
Joining the meeting
Joining meeting
Waiting for event
onLoginReturnWithReason - loginstatus 0, LoginFailReason 0
onMeetingStatusChanged - 7, result 0
MEETING_STATUS_ENDED
onMeetingStatusChanged - 1, result 0
MEETING_STATUS_CONNECTING
Setting up custom UI handling
Video container null on CreateVideoContainer: 7

```

**Output Without Custom UI Handling**

```auto
Starting app
Args 4
Meeting number #########
App key #########
App secret #########
Waiting for event
onAuthenticationReturn - 0
onAuthenticationReturn - AUTHRET_SUCCESS
Finished waiting for event
Creating Meeting Service
Joining the meeting
Joining meeting
Waiting for event
onMeetingStatusChanged - 1, result 0
MEETING_STATUS_CONNECTING
onMeetingStatusChanged - 2, result 0
MEETING_STATUS_WAITINGFORHOST

```

**Reference Code**

```auto
#include <windows.h>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include "zoom_sdk.h"
#include "auth_service_interface.h"
#include "meeting_service_interface.h"
#include "setting_service_interface.h"
#include "meeting_service_components/meeting_configuration_interface.h"
#include "customized_ui/zoom_customized_ui.h"
#include "customized_ui/customized_ui_mgr.h"
#include "customized_ui/customized_video_container.h"

void customUIInit();

class CustomUIEventHandler : public ZOOM_SDK_NAMESPACE::ICustomizedUIMgrEvent, public ZOOM_SDK_NAMESPACE::ICustomizedVideoContainerEvent {
    virtual void onVideoContainerDestroyed(ZOOM_SDK_NAMESPACE::ICustomizedVideoContainer* pContainer) {}
    virtual void onShareRenderDestroyed(ZOOM_SDK_NAMESPACE::ICustomizedShareRender* pRender) {}
    virtual void onRenderUserChanged(ZOOM_SDK_NAMESPACE::IVideoRenderElement *pElement, unsigned int userid) {}
    virtual void onRenderDataTypeChanged(ZOOM_SDK_NAMESPACE::IVideoRenderElement *pElement, ZOOM_SDK_NAMESPACE::VideoRenderDataType dataType) { }
    virtual void onLayoutNotification(RECT wnd_client_rect) { }
    virtual void onVideoRenderElementDestroyed(ZOOM_SDK_NAMESPACE::IVideoRenderElement *pElement) { }
    virtual void onWindowMsgNotification(UINT uMsg, WPARAM wParam, LPARAM lParam) { }
    virtual void onSubscribeUserFail(ZOOM_SDK_NAMESPACE::ZoomSDKVideoSubscribeFailReason fail_reason, ZOOM_SDK_NAMESPACE::IVideoRenderElement* pElement) {}
};

class ZoomServiceEventHandler : public ZOOM_SDK_NAMESPACE::IAuthServiceEvent, public ZOOM_SDK_NAMESPACE::IMeetingServiceEvent {
    public:
        ZoomServiceEventHandler() {}
        virtual ~ZoomServiceEventHandler() {}
        virtual void onAuthenticationReturn(ZOOM_SDK_NAMESPACE::AuthResult ret) {
            printf("onAuthenticationReturn - %d\n",ret);
            waitForEventFlag = false;
            errorFlag = true;
            if (ret == ZOOM_SDK_NAMESPACE::AUTHRET_SUCCESS) {
                printf("onAuthenticationReturn - AUTHRET_SUCCESS\n");
                errorFlag = false;
            } else if (ret == ZOOM_SDK_NAMESPACE::AUTHRET_JWTTOKENWRONG) {
                printf("onAuthenticationReturn - AUTHRET_JWTTOKENWRONG\n");
            } else if (ret == ZOOM_SDK_NAMESPACE::AUTHRET_KEYORSECRETWRONG) {
                printf("onAuthenticationReturn - AUTHRET_KEYORSECRETWRONG\n");
            } else {
                printf("onAuthenticationReturn - OTHER ERROR\n");
            }
        }
        virtual void onLoginRet(ZOOM_SDK_NAMESPACE::LOGINSTATUS ret, ZOOM_SDK_NAMESPACE::IAccountInfo* pAccountInfo) {
            printf("onLoginRet\n");
        }
        virtual void onLoginReturnWithReason(ZOOM_SDK_NAMESPACE::LOGINSTATUS ret, ZOOM_SDK_NAMESPACE::IAccountInfo* pAccountInfo, ZOOM_SDK_NAMESPACE::LoginFailReason reason) {
            printf("onLoginReturnWithReason - loginstatus %d, LoginFailReason %d\n",ret,reason);
        }
        virtual void onLogout() {
            printf("onLogout\n");
        }
        virtual void onZoomIdentityExpired() {
            printf("onZoomIdentityExpired\n");
        }
        virtual void onZoomAuthIdentityExpired() {
            printf("onZoomAuthIdentityExpired\n");
        }
        // Meeting service
        virtual void onMeetingStatusChanged(ZOOM_SDK_NAMESPACE::MeetingStatus status, int iResult=0) {
            printf("onMeetingStatusChanged - %d, result %d\n",status,iResult);
            if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_IDLE) {
                printf("MEETING_STATUS_IDLE\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_CONNECTING) {
                printf("MEETING_STATUS_CONNECTING\n");
                // https://marketplace.zoom.us/docs/sdk/native-sdks/windows/mastering-sdk/custom-ui-feature/
                // It is recommended to create the meeting service when you receive the onMeetingStatusChanged notification with the parameter MeetingStatus equalling ZOOM_SDK_NAMESPACE::MEETING_STATUS_CONNECTING. This allows you to work with the preview meeting function as well.
                customUIInit();
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_WAITINGFORHOST) {
                printf("MEETING_STATUS_WAITINGFORHOST\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_INMEETING) {
                printf("MEETING_STATUS_INMEETING\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_DISCONNECTING) {
                printf("MEETING_STATUS_DISCONNECTING\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_RECONNECTING) {
                printf("MEETING_STATUS_RECONNECTING\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_FAILED) {
                printf("MEETING_STATUS_FAILED\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_ENDED) {
                printf("MEETING_STATUS_ENDED\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_UNKNOW) {
                printf("MEETING_STATUS_UNKNOW\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_LOCKED) {
                printf("MEETING_STATUS_LOCKED\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_UNLOCKED) {
                printf("MEETING_STATUS_UNLOCKED\n");
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_IN_WAITING_ROOM) {
                printf("MEETING_STATUS_IN_WAITING_ROOM\n");
            } else {
                printf("UNKNOWN\n");
            }
        }
        virtual void onMeetingStatisticsWarningNotification (ZOOM_SDK_NAMESPACE::StatisticsWarningType type) {
            printf("onMeetingStatusChanged\n");
        }
        virtual void onMeetingParameterNotification(const ZOOM_SDK_NAMESPACE::MeetingParameter* meeting_param) {
            printf("onMeetingParameterNotification\n");
        }
        bool waitForEvent() {
            printf("Waiting for event\n");
            MSG msg;
            int bRet;
            waitForEventFlag = true;
            while (((bRet = GetMessage(&msg, nullptr, 0, 0)) != 0)&&(waitForEventFlag)) {
                //printf("Got message in windows event handler\n");
                if (bRet == -1) {
                    //printf("Error event\n");
                    // handle the error and possibly exit
                } else {
                    //printf("Not error event\n");
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            printf("Finished waiting for event\n");
            return errorFlag;
        }
        
    private:
        bool waitForEventFlag;
        bool errorFlag;
};

ZoomServiceEventHandler zoomServiceEventHandler;

void customUIInit() {
    // Custom UI stuff
    ZOOM_SDK_NAMESPACE::SDKError err;
    printf("Setting up custom UI handling\n");
    CustomUIEventHandler customUIEventHandler;
    ZOOM_SDK_NAMESPACE::ICustomizedUIMgr *uiManager;
    err = ZOOM_SDK_NAMESPACE::CreateCustomizedUIMgr(&uiManager);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("CreateCustomizedUIMgr failure - %d\n",err);
        exit(-1);
    }
    uiManager->SetEvent(&customUIEventHandler);
    HWND hParent = ::CreateWindowA("STATIC","dummy",WS_VISIBLE,0,0,200,200,NULL,NULL,NULL,NULL);
    ::SetWindowTextA(hParent,"Dummy Window!");
    RECT rc;
    GetWindowRect(hParent, &rc);
    rc.bottom = rc.bottom - 10;
    rc.top = rc.top + 10;
    rc.right = rc.right - 10;
    rc.left = rc.left + 10;

    ZOOM_SDK_NAMESPACE::ICustomizedVideoContainer* videoContainer = NULL;
    err = uiManager->CreateVideoContainer(&videoContainer, hParent, rc);
    if (videoContainer == NULL) {
        // We hit this condition, err is 7 = SDKERR_UNINITIALIZE
        printf("Video container null on CreateVideoContainer: %d\n",err);
        exit(0);
    }
    videoContainer->SetEvent(&customUIEventHandler);
    videoContainer->Show();
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR , int nCmdShow) {
    AllocConsole();
    freopen("CONOUT$", "w", stdout);
    printf("Starting app\n");
    int argCount;
    LPWSTR *szArgList = CommandLineToArgvW(GetCommandLineW(), &argCount);
    printf("Args %d\n",argCount);
    if (argCount != 4) {
        printf("Usage: winpoc.exe <meeting id> <app key> <app secret>\n");
        return 0;
    }
    std::wstring meetingNumber = szArgList[1];
    std::wstring appKey = szArgList[2];
    std::wstring appSecret = szArgList[3];
    printf("Meeting number %ls\n",meetingNumber.c_str());
    printf("App key %ls\n",appKey.c_str());
    printf("App secret %ls\n",appSecret.c_str());
    ZOOM_SDK_NAMESPACE::InitParam initParam;
    initParam.strWebDomain = L"https://zoom.us";
    initParam.strSupportUrl = L"https://zoom.us";
    // Request Custom UI feature - see https://marketplace.zoom.us/docs/sdk/native-sdks/windows/mastering-sdk/custom-ui-feature/
    initParam.obConfigOpts.optionalFeatures = (1 << 5);
    initParam.enableLogByDefault = true;
    //initParam.enableGenerateDump = true;
    ZOOM_SDK_NAMESPACE::SDKError err = ZOOM_SDK_NAMESPACE::InitSDK(initParam);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("failed InitSDK\n");
        return -1;
    }
    ZOOM_SDK_NAMESPACE::IAuthService *authService;
    err = ZOOM_SDK_NAMESPACE::CreateAuthService(&authService);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("failed CreateAuthService\n");
        return -1;
    }
    authService->SetEvent(&zoomServiceEventHandler);
    // Auth using key and secret
    ZOOM_SDK_NAMESPACE::AuthParam authParam;
    authParam.appKey = appKey.c_str();
    authParam.appSecret = appSecret.c_str();
    err = authService->SDKAuth(authParam); // AUTHRET_KEYORSECRETWRONG
    // Do the auth
    if(ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("Failed SDKAuth\n");
        return -1;
    }
    // Creating auth thread
    if (zoomServiceEventHandler.waitForEvent()) {
        printf("Error!!\n");
        return -1;
    }
    // Get meeting service - this is working
    printf("Creating Meeting Service\n");
    ZOOM_SDK_NAMESPACE::IMeetingService* meetingService;
    err = ZOOM_SDK_NAMESPACE::CreateMeetingService(&meetingService);
    if(ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("failed GetMeetingService\n");
        return -1;
    }
    meetingService->SetEvent(&zoomServiceEventHandler);

    // Get setting service - this is working
    if (meetingService->GetMeetingConfiguration())
        meetingService->GetMeetingConfiguration()->SetSharingToolbarVisibility(false);
    ZOOM_SDK_NAMESPACE::ISettingService* _setting_service;
    ZOOM_SDK_NAMESPACE::CreateSettingService(&_setting_service);
    if (!_setting_service) {
        printf("failed CreateSettingService\n");
        return -1;
    }

    printf("Joining the meeting\n");
    ZOOM_SDK_NAMESPACE::tagJoinParam joinParam;
    joinParam.userType = ZOOM_SDK_NAMESPACE::SDK_UT_WITHOUT_LOGIN;
    ZOOM_SDK_NAMESPACE::JoinParam4WithoutLogin& withoutloginParam = joinParam.param.withoutloginuserJoin;
    withoutloginParam.meetingNumber = _wtoi64(meetingNumber.c_str());
    withoutloginParam.vanityID = NULL;
    withoutloginParam.userName = L"My PoC";
    withoutloginParam.psw = L"#######";
    withoutloginParam.hDirectShareAppWnd = NULL;
    withoutloginParam.customer_key = NULL;
    withoutloginParam.webinarToken = NULL;
    withoutloginParam.isDirectShareDesktop = false;
    withoutloginParam.isVideoOff = false;
    withoutloginParam.isAudioOff = false;
    printf("Joining meeting\n");
    err = meetingService->Join(joinParam);
    if (err != ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS) {
        printf("Error on join meeting %d\n",err);
        return -1;
    }
    if (zoomServiceEventHandler.waitForEvent()) {
        printf("Error!!\n");
        return -1;
    }
    printf("Waiting ...\n");
    sleep(20);
    printf("Finished app\n");
    return 0;
}

```

---

<div class="post-metadata">

**Author:** ![jon.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/jon.zoom/32/13495_2.png) [@jon.zoom](https://devforum.zoom.us/u/jon.zoom)\
**Post date:** [April 19, 2022, 9:06pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/8 "2022-04-19T21:06:45Z")

</div>

Hi @max_dev,

There is a lot of extraneous code/information in the snippet and log output you’ve provided. Let’s try to distill this information down to just the usages of the SDK, when they happen, and the return values of each one.

Thanks!

---

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [April 24, 2022, 7:44pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/9 "2022-04-24T19:44:06Z")

</div>

Hi @jon.zoom - hmm, I think the code I included is pretty much the minimal use of the SDK to join a meeting with custom UI - all code I’ve provided relates directly to SDK usage (I’ve pared it back a little further to 180 lines below). I wanted to show that I can successfully join the meeting without custom UI feature, but when I start to use the custom UI feature, it fails to create a video container with the error `SDKERR_UNINITIALIZE`. The only difference in code being the call to the `customUIInit` function (and also SDK initialisation for custom ui in `initParam.obConfigOpts.optionalFeatures = (1 << 5);`).

Let me know if I can provide any further info that would help. Thanks!

```auto
#include <windows.h>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include "zoom_sdk.h"
#include "auth_service_interface.h"
#include "meeting_service_interface.h"
#include "setting_service_interface.h"
#include "meeting_service_components/meeting_configuration_interface.h"
#include "customized_ui/zoom_customized_ui.h"
#include "customized_ui/customized_ui_mgr.h"
#include "customized_ui/customized_video_container.h"

void customUIInit();

class CustomUIEventHandler : public ZOOM_SDK_NAMESPACE::ICustomizedUIMgrEvent, public ZOOM_SDK_NAMESPACE::ICustomizedVideoContainerEvent {
    virtual void onVideoContainerDestroyed(ZOOM_SDK_NAMESPACE::ICustomizedVideoContainer* pContainer) {}
    virtual void onShareRenderDestroyed(ZOOM_SDK_NAMESPACE::ICustomizedShareRender* pRender) {}
    virtual void onRenderUserChanged(ZOOM_SDK_NAMESPACE::IVideoRenderElement *pElement, unsigned int userid) {}
    virtual void onRenderDataTypeChanged(ZOOM_SDK_NAMESPACE::IVideoRenderElement *pElement, ZOOM_SDK_NAMESPACE::VideoRenderDataType dataType) { }
    virtual void onLayoutNotification(RECT wnd_client_rect) { }
    virtual void onVideoRenderElementDestroyed(ZOOM_SDK_NAMESPACE::IVideoRenderElement *pElement) { }
    virtual void onWindowMsgNotification(UINT uMsg, WPARAM wParam, LPARAM lParam) { }
    virtual void onSubscribeUserFail(ZOOM_SDK_NAMESPACE::ZoomSDKVideoSubscribeFailReason fail_reason, ZOOM_SDK_NAMESPACE::IVideoRenderElement* pElement) {}
};

class ZoomServiceEventHandler : public ZOOM_SDK_NAMESPACE::IAuthServiceEvent, public ZOOM_SDK_NAMESPACE::IMeetingServiceEvent {
    public:
        ZoomServiceEventHandler() {}
        virtual ~ZoomServiceEventHandler() {}
        virtual void onLoginRet(ZOOM_SDK_NAMESPACE::LOGINSTATUS ret, ZOOM_SDK_NAMESPACE::IAccountInfo* pAccountInfo) {}
        virtual void onLoginReturnWithReason(ZOOM_SDK_NAMESPACE::LOGINSTATUS ret, ZOOM_SDK_NAMESPACE::IAccountInfo* pAccountInfo, ZOOM_SDK_NAMESPACE::LoginFailReason reason) {}
        virtual void onLogout() {}
        virtual void onZoomIdentityExpired() {}
        virtual void onZoomAuthIdentityExpired() {}
        virtual void onAuthenticationReturn(ZOOM_SDK_NAMESPACE::AuthResult ret) {
            printf("onAuthenticationReturn - %d\n",ret);
            waitForEventFlag = false;
            errorFlag = true;
            if (ret == ZOOM_SDK_NAMESPACE::AUTHRET_SUCCESS) errorFlag = false;
        }
        // Meeting service
        virtual void onMeetingStatusChanged(ZOOM_SDK_NAMESPACE::MeetingStatus status, int iResult=0) {
            if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_CONNECTING) {
                printf("MEETING_STATUS_CONNECTING\n");
                // https://marketplace.zoom.us/docs/sdk/native-sdks/windows/mastering-sdk/custom-ui-feature/
                // It is recommended to create the meeting service when you receive the onMeetingStatusChanged notification with the parameter MeetingStatus equalling ZOOM_SDK_NAMESPACE::MEETING_STATUS_CONNECTING. This allows you to work with the preview meeting function as well.
                customUIInit();
            } else if (status == ZOOM_SDK_NAMESPACE::MEETING_STATUS_WAITINGFORHOST) {
                printf("MEETING_STATUS_WAITINGFORHOST\n");
            } else {
                printf("Meeting status %d\n",status);
            }
        }
        virtual void onMeetingStatisticsWarningNotification (ZOOM_SDK_NAMESPACE::StatisticsWarningType type) {}
        virtual void onMeetingParameterNotification(const ZOOM_SDK_NAMESPACE::MeetingParameter* meeting_param) {}
        bool waitForEvent() {
            MSG msg;
            int bRet;
            waitForEventFlag = true;
            while (((bRet = GetMessage(&msg, nullptr, 0, 0)) != 0)&&(waitForEventFlag)) {
                if (bRet == -1) {
                } else {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
            }
            return errorFlag;
        }
    private:
        bool waitForEventFlag;
        bool errorFlag;
};

ZoomServiceEventHandler zoomServiceEventHandler;

void customUIInit() {
    // Custom UI stuff
    ZOOM_SDK_NAMESPACE::SDKError err;
    printf("Setting up custom UI handling\n");
    CustomUIEventHandler customUIEventHandler;
    ZOOM_SDK_NAMESPACE::ICustomizedUIMgr *uiManager;
    err = ZOOM_SDK_NAMESPACE::CreateCustomizedUIMgr(&uiManager);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) {
        printf("CreateCustomizedUIMgr failure - %d\n",err);
        exit(-1);
    }
    uiManager->SetEvent(&customUIEventHandler);
    HWND hParent = ::CreateWindowA("STATIC","dummy",WS_VISIBLE,0,0,200,200,NULL,NULL,NULL,NULL);
    ::SetWindowTextA(hParent,"Dummy Window!");
    RECT rc;
    GetWindowRect(hParent, &rc);
    rc.bottom = rc.bottom - 10;
    rc.top = rc.top + 10;
    rc.right = rc.right - 10;
    rc.left = rc.left + 10;

    ZOOM_SDK_NAMESPACE::ICustomizedVideoContainer* videoContainer = NULL;
    err = uiManager->CreateVideoContainer(&videoContainer, hParent, rc);
    if (videoContainer == NULL) {
        // We hit this condition, err is 7 = SDKERR_UNINITIALIZE
        printf("Video container null on CreateVideoContainer: %d\n",err);
        exit(0);
    }
    videoContainer->SetEvent(&customUIEventHandler);
    videoContainer->Show();
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR , int nCmdShow) {
    AllocConsole();
    freopen("CONOUT$", "w", stdout);
    printf("Starting app\n");
    int argCount;
    LPWSTR *szArgList = CommandLineToArgvW(GetCommandLineW(), &argCount);
    printf("Args %d\n",argCount);
    if (argCount != 4) {
        printf("Usage: winpoc.exe <meeting id> <app key> <app secret>\n");
        return 0;
    }
    std::wstring meetingNumber = szArgList[1];
    std::wstring appKey = szArgList[2];
    std::wstring appSecret = szArgList[3];
    printf("Meeting number %ls\n",meetingNumber.c_str());
    printf("App key %ls\n",appKey.c_str());
    printf("App secret %ls\n",appSecret.c_str());
    ZOOM_SDK_NAMESPACE::InitParam initParam;
    initParam.strWebDomain = L"https://zoom.us";
    initParam.strSupportUrl = L"https://zoom.us";
    // Request Custom UI feature - see https://marketplace.zoom.us/docs/sdk/native-sdks/windows/mastering-sdk/custom-ui-feature/
    //initParam.obConfigOpts.optionalFeatures = (1 << 5);
    initParam.enableLogByDefault = true;
    ZOOM_SDK_NAMESPACE::SDKError err = ZOOM_SDK_NAMESPACE::InitSDK(initParam);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) return -1;
    ZOOM_SDK_NAMESPACE::IAuthService *authService;
    err = ZOOM_SDK_NAMESPACE::CreateAuthService(&authService);
    if (ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) return -1;
    authService->SetEvent(&zoomServiceEventHandler);
    // Auth using key and secret
    ZOOM_SDK_NAMESPACE::AuthParam authParam;
    authParam.appKey = appKey.c_str();
    authParam.appSecret = appSecret.c_str();
    err = authService->SDKAuth(authParam); // AUTHRET_KEYORSECRETWRONG
    // Do the auth
    if(ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) return -1;
    if (zoomServiceEventHandler.waitForEvent()) return -1;
    // Get meeting service - this is working
    printf("Creating Meeting Service\n");
    ZOOM_SDK_NAMESPACE::IMeetingService* meetingService;
    err = ZOOM_SDK_NAMESPACE::CreateMeetingService(&meetingService);
    if(ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS != err) return -1;
    meetingService->SetEvent(&zoomServiceEventHandler);

    // Get setting service - this is working
    if (meetingService->GetMeetingConfiguration()) meetingService->GetMeetingConfiguration()->SetSharingToolbarVisibility(false);
    ZOOM_SDK_NAMESPACE::ISettingService* _setting_service;
    ZOOM_SDK_NAMESPACE::CreateSettingService(&_setting_service);
    if (!_setting_service) return -1;
    printf("Joining the meeting\n");
    ZOOM_SDK_NAMESPACE::tagJoinParam joinParam;
    joinParam.userType = ZOOM_SDK_NAMESPACE::SDK_UT_WITHOUT_LOGIN;
    ZOOM_SDK_NAMESPACE::JoinParam4WithoutLogin& withoutloginParam = joinParam.param.withoutloginuserJoin;
    withoutloginParam.meetingNumber = _wtoi64(meetingNumber.c_str());
    withoutloginParam.vanityID = NULL;
    withoutloginParam.userName = L"My PoC";
    withoutloginParam.psw = L"XXXXX";
    withoutloginParam.hDirectShareAppWnd = NULL;
    withoutloginParam.customer_key = NULL;
    withoutloginParam.webinarToken = NULL;
    withoutloginParam.isDirectShareDesktop = false;
    withoutloginParam.isVideoOff = false;
    withoutloginParam.isAudioOff = false;
    printf("Joining meeting\n");
    err = meetingService->Join(joinParam);
    if (err != ZOOM_SDK_NAMESPACE::SDKERR_SUCCESS) return -1;
    if (zoomServiceEventHandler.waitForEvent()) return -1;
    printf("Waiting ...\n");
    sleep(20);
    printf("Finished app\n");
    return 0;
}

```

---

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [May 1, 2022, 11:20am UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/10 "2022-05-01T11:20:53Z")

</div>

Hi @jon.zoom - let me know if there’s any other information I can provide to progress this. I have zoom sdk logs as well if it is of any help? Thanks

---

<div class="post-metadata">

**Author:** ![jon.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/jon.zoom/32/13495_2.png) [@jon.zoom](https://devforum.zoom.us/u/jon.zoom)\
**Post date:** [May 3, 2022, 6:50pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/11 "2022-05-03T18:50:48Z")

</div>

Hi @max_dev,

No updates on this yet, but yes if you could provide the SDK logs that may be helpful. You can’t upload the logs directly to the dev forum, so you can either host them on file sharing service or submit them in a ticket through the [developer support site](https://zoomdevelopersupport.zendesk.com/hc/en-us). 🙂

Thanks!

---

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [May 22, 2022, 6:48pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/12 "2022-05-22T18:48:20Z")

</div>

Thanks @jon.zoom - logs available at [winpoc.exe\_Video\_0.log - Google Drive](https://drive.google.com/file/d/1C6OJdFtWlaxXnhpgCuCmPyvyuXKbpelS/view?usp=sharing) - let me know if I can provide any further info.

---

<div class="post-metadata">

**Author:** ![jon.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/jon.zoom/32/13495_2.png) [@jon.zoom](https://devforum.zoom.us/u/jon.zoom)\
**Post date:** [May 24, 2022, 6:50pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/13 "2022-05-24T18:50:46Z")

</div>

Hi @max_dev,

Thanks for providing the logs. We’ll keep you updated as soon as we have any new information.

Thanks!

---

<div class="post-metadata">

**Author:** ![max\_dev](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/max_dev/32/34269_2.png) [@max\_dev](https://devforum.zoom.us/u/max_dev)\
**Post date:** [May 30, 2022, 7:37pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/14 "2022-05-30T19:37:10Z")

</div>

Thanks @jon.zoom - let me know how it goes!

---

<div class="post-metadata">

**Author:** ![jon.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/jon.zoom/32/13495_2.png) [@jon.zoom](https://devforum.zoom.us/u/jon.zoom)\
**Post date:** [June 1, 2022, 7:13pm UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/15 "2022-06-01T19:13:59Z")

</div>

Hi @max_dev,

Based on the logs, there is an issue with loading `zSDK.dll`. Can you please confirm whether this was included in your project and whether it has been signed?

Thanks!

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex016/uploads/zoomdeveloper/original/3X/6/1/614bdd549b610bbaa46ff934617683a02bdaa03c.png) [@system](https://devforum.zoom.us/u/system)\
**Post date:** [July 2, 2022, 5:14am UTC](https://devforum.zoom.us/t/license-error-using-custom-ui-feature-in-windows-sdk/66480/16 "2022-07-02T05:14:33Z")

</div>

Closed on July 2, 2022, 5:14am UTC

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.
