Responding to Parallels Service QuestionsOne of the event types in the Handling of the event involves the following steps (we skip the general event handling steps described in the previous section):
The following is a complete example that demonstrates how to handle events of type #include "Parallels.h" #include "Wrappers/SdkWrap/SdkWrap.h" #include <stdio.h> #include <stdlib.h>
#ifdef _WIN_ #include <windows.h> #else #include <unistd.h> #endif
#define MY_JOB_TIMEOUT 10000 // Default timeout. #define MY_HDD_SIZE 70*1024 // The size of the new hard drive. #define MY_STR_BUF_SIZE 1024 // The default string buffer size.
////////////////////////////////////////////////////////////////////////////////
// A helper function that will attempt to create a hard drive larger // than the free space available, thus triggering an event on the // server. static PRL_RESULT create_big_hdd(PRL_HANDLE hVm);
// The callback function (event handler). static PRL_RESULT callback(PRL_HANDLE, PRL_VOID_PTR);
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[]) { // Pick the correct dynamic library file depending on the platform. #ifdef _WIN_ #define SDK_LIB_NAME "prl_sdk.dll" #elif defined(_LIN_) #define SDK_LIB_NAME "libprl_sdk.so" #elif defined(_MAC_) #define SDK_LIB_NAME "libprl_sdk.dylib" #endif
// Load the dynamic library. if (PRL_FAILED(SdkWrap_Load(SDK_LIB_NAME)) && PRL_FAILED(SdkWrap_Load("./" SDK_LIB_NAME))) { // Error handling goes here... return -1; }
PRL_RESULT ret = PRL_ERR_UNINITIALIZED; PRL_RESULT err = PRL_ERR_UNINITIALIZED; PRL_RESULT rc = PRL_ERR_UNINITIALIZED; PRL_HANDLE hJob = PRL_INVALID_HANDLE; PRL_HANDLE hJobResult = PRL_INVALID_HANDLE; PRL_HANDLE hServer = PRL_INVALID_HANDLE;
// Initialize API library. In this example, we are initializing the // API for Parallels Server. // To initialize in the Parallels Desktop mode, pass PAM_DESKTOP // as the second parameter. // To initialize for Parallels Workstation, pass PAM_WORKSTATION. // See the PRL_APPLICATION_MODE enumeration for other options. err = PrlApi_InitEx(PARALLELS_API_VER, PAM_SERVER, 0, 0); if (PRL_FAILED(err)) { // Error handling goes here... return -1; }
// Create server object. PrlSrv_Create(&hServer);
// Log in. hJob = PrlSrv_Login( hServer, // Server handle "10.30.22.82", // Server IP address "jdoe", // User "secret", // Password 0, // Previous session ID 0, // Port number 0, // Timeout PSL_NORMAL_SECURITY); // Security
ret = PrlJob_Wait(hJob, MY_JOB_TIMEOUT); PrlHandle_Free(hJob);
if (PRL_FAILED(ret)) { fprintf(stderr, "PrlJob_Wait for PrlSrv_Login returned with error: %s\n", prl_result_to_string(ret)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Analyze the result of PrlSrv_Login. PRL_RESULT nJobResult; ret = PrlJob_GetRetCode( hJob, &nJobResult ); if (PRL_FAILED( nJobResult)) { PrlHandle_Free(hJob); PrlHandle_Free(hServer); printf( "Login job returned with error: %s\n", prl_result_to_string(nJobResult)); PrlHandle_Free(hJob); PrlHandle_Free(hServer); PrlApi_Deinit(); SdkWrap_Unload(); return -1; }
// Create a new virtual machine. PRL_HANDLE hVm = PRL_INVALID_HANDLE; PrlSrv_CreateVm(hServer, &hVm); PrlVmCfg_SetName(hVm, "My simple VM");
// Register the virtual machine with the Service hJob = PrlVm_Reg(hVm, "", PRL_FALSE); PrlJob_Wait(hJob, MY_JOB_TIMEOUT); PrlHandle_Free(hJob);
// Register the event handler with the Service. // The second parameter is a pointer to our callback function. PrlSrv_RegEventHandler(hServer, &callback, NULL);
// Try creating a virtual hard drive larger than the // free space available (increase MY_HDD_SIZE value if needed). // This should produce an event that will // contain a question from the Service. // We create the drive using a simple helper function. // The function is listed at the end of the example. create_big_hdd(hVm);
// // At this point, the background thread should call the // callback function. //
// We can now clean up and exit the program. // Unregister the event handler and log off. PrlSrv_UnregEventHandler(hServer, &callback, NULL); hJob = PrlSrv_Logoff(hServer); PrlJob_Wait(hJob, MY_JOB_TIMEOUT); PrlHandle_Free( hJob ); PrlHandle_Free( hServer ); PrlApi_Deinit(); SdkWrap_Unload(); return 0; }
//////////////////////////////////////////////////////////////////////////////// // The callback function implementation. // The event handling is demonstrated here. // static PRL_RESULT callback(PRL_HANDLE hEvent, PRL_VOID_PTR pUserData) { PRL_HANDLE_TYPE nHandleType; PrlHandle_GetType(hEvent, &nHandleType);
// A callback function will be called more than once. // It will be called for every job that we initiate and it // will be called for the event that we intentionally trigger. // In this example, we are interested in events only. if (nHandleType != PHT_EVENT) { return PrlHandle_Free(hEvent); }
// Get the type of the event received. PRL_EVENT_TYPE type; PrlEvent_GetType(hEvent, &type);
// See if the received event is a "question". if (type == PET_DSP_EVT_VM_QUESTION) { PRL_UINT32 nParamsCount = 0; PRL_RESULT err = PRL_ERR_UNINITIALIZED;
// Extract the text of the question and display it on the screen. PRL_BOOL bIsBriefMessage = true; char errMsg [MY_STR_BUF_SIZE]; PRL_UINT32 nBufSize = MY_STR_BUF_SIZE; PrlEvent_GetErrString(hEvent, bIsBriefMessage, errMsg, &nBufSize); printf("Question: %s\n\n", errMsg);
// Extract possible answers. They are stored in the // hEvent object as event parameters. // First, determine the number of parameters. err = PrlEvent_GetParamsCount(hEvent, &nParamsCount); if (PRL_FAILED(err)) { fprintf(stderr, "[3]%.8X: %s\n", err, prl_result_to_string(err)); PrlHandle_Free(hEvent); return err; }
// Declare an array to hold the answer choices. PRL_UINT32_PTR choices =(PRL_UINT32_PTR) malloc(nParamsCount * sizeof(PRL_UINT32));
// Now, itereate through the parameter list obtaining a // handle of type PHT_EVENT_PARAMETER containing an individual // parameter data. for(PRL_UINT32 nParamIndex = 0; nParamIndex < nParamsCount; ++nParamIndex) { PRL_HANDLE hParam = PRL_INVALID_HANDLE; PRL_RESULT err = PRL_ERR_UNINITIALIZED;
// The PrlEvent_GetParam function obtains a handle of type // PHT_EVENT_PARAMETER containing an answer choice. err = PrlEvent_GetParam(hEvent, nParamIndex, &hParam); if (PRL_FAILED(err)) { fprintf(stderr, "[4]%.8X: %s\n", err, prl_result_to_string(err)); PrlHandle_Free(hParam); PrlHandle_Free(hEvent); return err; }
// Get the answer description that can be shown to the user. // First, obtain the event parameter value. err = PrlEvtPrm_ToUint32(hParam, &choices[nParamIndex]); if (PRL_FAILED(err)) { fprintf(stderr, "[9]%.8X: %s\n", err, prl_result_to_string(err)); PrlHandle_Free(hParam); PrlHandle_Free(hEvent); return err; } // Now, get the answer description using the // event parameter value as input in the following call. char sDesc [MY_STR_BUF_SIZE]; err = PrlApi_GetResultDescription(choices[nParamIndex], true, sDesc, &nBufSize); if (PRL_FAILED(err)) { fprintf(stderr, "[8]%.8X: %s\n", err, prl_result_to_string(err)); PrlHandle_Free(hParam); PrlHandle_Free(hEvent); return err; }
// Display the answer choice on the screen. printf("Answer choice: %s\n", sDesc); PrlHandle_Free(hParam); }
// Select an answer choice (we are simply using the "No" // answer here) and create a valid answer object (hAnswer). PRL_HANDLE hAnswer = PRL_INVALID_HANDLE; err = PrlEvent_CreateAnswerEvent(hEvent, &hAnswer, choices[1]); if (PRL_FAILED(err)) { fprintf(stderr, "[A]%.8X: %s\n", err, prl_result_to_string(err)); PrlHandle_Free(hEvent); return err; }
// Obtain a server handle. We need it to send an answer. PRL_HANDLE hServer = PRL_INVALID_HANDLE; PrlEvent_GetServer(hEvent, &hServer);
// Send the handle containing the answer data to the Parallels Service. PrlSrv_SendAnswer(hServer, hAnswer);
free(choices); PrlHandle_Free(hServer); PrlHandle_Free(hAnswer); } else // other event type { PrlHandle_Free(hEvent); }
return PRL_ERR_SUCCESS; }
////////////////////////////////////////////////////////////////////////////////
// A helper function that will attempt to crate a hard drive larger // than the free space available, thus triggering an event. PRL_RESULT create_big_hdd(PRL_HANDLE hVm) { PRL_HANDLE hJobBeginEdit = PRL_INVALID_HANDLE; PRL_HANDLE hJobCommit = PRL_INVALID_HANDLE; PRL_HANDLE hJob = PRL_INVALID_HANDLE; PRL_RESULT nJobRetCode = PRL_ERR_UNINITIALIZED; PRL_RESULT err = PRL_ERR_UNINITIALIZED;
// Timestamp the beginning of the configuration changes operation. hJobBeginEdit = PrlVm_BeginEdit(hVm); err = PrlJob_Wait(hJobBeginEdit, MY_JOB_TIMEOUT); PrlJob_GetRetCode(hJobBeginEdit, &nJobRetCode); if (PRL_FAILED(nJobRetCode)) { fprintf(stderr, "[B]%.8X: %s\n", nJobRetCode, prl_result_to_string(nJobRetCode)); PrlHandle_Free(hJobBeginEdit); return nJobRetCode; }
// Create a new device handle. // This will be our new virtual hard disk. PRL_HANDLE hHDD = PRL_INVALID_HANDLE; err = PrlVmCfg_CreateVmDev( hVm, // Target virtual machine. PDE_HARD_DISK, // Device type. &hHDD ); // Device handle.
// Set disk type to "expanding". err = PrlVmDevHd_SetDiskType(hHDD, PHD_EXPANDING_HARD_DISK);
// Set max disk size, in megabytes. err = PrlVmDevHd_SetDiskSize(hHDD, MY_HDD_SIZE);
// This option determines whether the image file will be split // into chunks or created as a single file. err = PrlVmDevHd_SetSplitted(hHDD, PRL_FALSE);
// Choose and set the name for the new image file. err = PrlVmDev_SetFriendlyName(hHDD, "harddisk4.hdd"); err = PrlVmDev_SetSysName(hHDD, "harddisk4.hdd");
// Set the emulation type. err = PrlVmDev_SetEmulatedType(hHDD, PDT_USE_IMAGE_FILE);
// Enable the new disk on successful creation. err = PrlVmDev_SetEnabled(hHDD, PRL_TRUE);
// Create the new image file. hJob = PrlVmDev_CreateImage(hHDD, PRL_TRUE, // Do not overwrite if file exists. PRL_FALSE ); // Use non-interactive mode.
err = PrlJob_Wait(hJob, MY_JOB_TIMEOUT); if (PRL_FAILED(err)) { fprintf(stderr, "[C]%.8X: %s\n", err, prl_result_to_string(err)); PrlHandle_Free(hJob); return err; }
// Commit the changes. hJobCommit = PrlVm_Commit(hVm); err = PrlJob_Wait(hJobCommit, MY_JOB_TIMEOUT); PrlJob_GetRetCode(hJobCommit, &nJobRetCode); if (PRL_FAILED(nJobRetCode)) { fprintf(stderr, "[D]%.8X: %s\n", nJobRetCode, prl_result_to_string( nJobRetCode)); PrlHandle_Free(hJobCommit); return nJobRetCode; } return PRL_ERR_SUCCESS; }
|
||||
|