Re: DSMPlugin.cpp issue [was: MSRC4 DSM requires write permission in UltraVNC folder?]
Charles Duffy <[email protected]> Sat, 01 Oct 2005 07:48:04 -0500
| Newsgroups | gmane.network.vnc.ultravnc.general |
|---|---|
| Message-ID | <[email protected]> |
Sean Covel wrote: > This is actually a bad hack that doesn't work (I'm pretty sure it > doesn't work even if you DO have write access) and should be removed. If > you haven't posted anything on the UltraVNC forum about this problem you > should! I have a patch intended to work around this issue. Emphasis on *intended* - I can't test it (beyond making sure it compiles with GCC) as I don't own a copy of Visual Studio; no Free compilers are supported by UltraVNC; and my Borland support patch doesn't cover building DSMs. That said, it's probably pretty close to what's actually needed to do the trick, and should at least serve as a demonstration of one appropriate fix. Sean, I'd be curious to know if it Works For You (in terms of both the design and implementation). (I haven't cross-posted this to the forum yet as it appears to be down on account of the $#^%! excuse for a database they're backending into).
DSMPluginRearchitect.patch
(text/plain, 19 KB)
diff -ru3 UltraVnc-101-src/src/ultravnc/DSMPlugin/DSMPlugin.cpp UltraVnc-101-src.new/src/ultravnc/DSMPlugin/DSMPlugin.cpp
--- UltraVnc-101-src/src/ultravnc/DSMPlugin/DSMPlugin.cpp 2005-01-15 15:32:52.000000000 -0600
+++ UltraVnc-101-src.new/src/ultravnc/DSMPlugin/DSMPlugin.cpp 2005-10-01 07:43:39.703125000 -0500
@@ -89,7 +89,7 @@
lpString++;
}
*szToken = '\0' ;
- if (( ! *lpString ) || (! *szToken)) return NULL;
+ if (( ! *lpString ) || (! *szToken)) return FALSE;
return FALSE;
}
@@ -125,6 +125,8 @@
TRANSFORMBUFFER m_PFreeBuffer = NULL;
RESET m_PReset = NULL;
+ context = NULL;
+
}
//
@@ -135,6 +137,11 @@
// TODO: Log events
if (IsLoaded())
UnloadPlugin();
+#if 0
+ // TODO: if context isn't NULL, throw a warning that the plugin author screwed up.
+ if (context != NULL)
+ delete *context;
+#endif
}
@@ -188,7 +195,7 @@
bool CDSMPlugin::InitPlugin(void)
{
// TODO: Log events
- int nRes = (*m_PStartup)();
+ int nRes = (*m_PStartup)(&context, m_hPDll);
if (nRes < 0) return false;
else return true;
}
@@ -199,7 +206,7 @@
bool CDSMPlugin::ResetPlugin(void)
{
// TODO: Log events
- int nRes = (*m_PReset)();
+ int nRes = (*m_PReset)(&context);
if (nRes < 0) return false;
else return true;
}
@@ -211,7 +218,7 @@
bool CDSMPlugin::SetPluginParams(HWND hWnd, char* szParams)
{
// TODO: Log events
- int nRes = (*m_PSetParams)(hWnd, szParams);
+ int nRes = (*m_PSetParams)(&context, hWnd, szParams);
if (nRes > 0) return true; else return false;
}
@@ -223,7 +230,7 @@
char* CDSMPlugin::GetPluginParams(void)
{
//
- return (*m_PGetParams)();
+ return (*m_PGetParams)(&context);
}
@@ -280,34 +287,8 @@
//
bool CDSMPlugin::LoadPlugin(char* szPlugin, bool fAllowMulti)
{
- // sf@2003 - Multi dll trick
- // I really don't like doing this kind of dirty workaround but I have no time to do
- // better for now. Used only by a listening viewer.
- // Create a numbered temporary copy of the original plugin dll and load it (viewer only, for now)
- if (fAllowMulti)
- {
- bool fDllCopyCreated = false;
- int i = 1;
- char szDllCopyName[196];
- while (!fDllCopyCreated)
- {
- strcpy(szDllCopyName, szPlugin);
- szDllCopyName[strlen(szPlugin) - 4] = '\0'; //remove the ".dsm" extension
- sprintf(szDllCopyName, "%s-tmp.d%d", szDllCopyName, i++);
- fDllCopyCreated = (bool) CopyFile(szPlugin, szDllCopyName, false);
- // Note: Let's be really dirty; Overwrite if it's possible only (dll not loaded).
- // This way if for some reason (abnormal process termination) the dll wasn't previously
- // normally deleted we overwrite/clean it with the new one at the same time.
- if (i > 99) break; // Just in case...
- }
- strcpy(m_szDllName, szDllCopyName);
- m_hPDll = LoadLibrary(m_szDllName);
- }
- else // Use the original plugin dll
- {
- ZeroMemory(m_szDllName, strlen(m_szDllName));
- m_hPDll = LoadLibrary(szPlugin);
- }
+ ZeroMemory(m_szDllName, strlen(m_szDllName));
+ m_hPDll = LoadLibrary(szPlugin);
if (m_hPDll == NULL) return false;
@@ -342,15 +323,15 @@
{
// TODO: Log events
// Force the DSMplugin to free the buffers it allocated
- if (m_pTransBuffer != NULL) (*m_PFreeBuffer)(m_pTransBuffer);
- if (m_pRestBuffer != NULL) (*m_PFreeBuffer)(m_pRestBuffer);
+ if (m_pTransBuffer != NULL) (*m_PFreeBuffer)(&context, m_pTransBuffer);
+ if (m_pRestBuffer != NULL) (*m_PFreeBuffer)(&context, m_pRestBuffer);
m_pTransBuffer = NULL;
m_pRestBuffer = NULL;
SetLoaded(false);
- if ((*m_PShutdown)())
+ if ((*m_PShutdown)(&context))
{
bool fFreed = false;
fFreed = FreeLibrary(m_hPDll);
@@ -373,7 +354,7 @@
// FixME: possible pb with this mutex in WinVNC
omni_mutex_lock l(m_TransMutex);
- m_pTransBuffer = (*m_PTransformBuffer)(pDataBuffer, nDataLen, pnTransformedDataLen);
+ m_pTransBuffer = (*m_PTransformBuffer)(&context, pDataBuffer, nDataLen, pnTransformedDataLen);
return m_pTransBuffer;
}
@@ -385,13 +366,13 @@
BYTE* CDSMPlugin::RestoreBufferStep1(BYTE* pRestoredDataBuffer, int nDataLen, int* pnRestoredDataLen)
{
//m_RestMutex.lock();
- m_pRestBuffer = (*m_PRestoreBuffer)(pRestoredDataBuffer, nDataLen, pnRestoredDataLen);
+ m_pRestBuffer = (*m_PRestoreBuffer)(&context, pRestoredDataBuffer, nDataLen, pnRestoredDataLen);
return m_pRestBuffer;
}
BYTE* CDSMPlugin::RestoreBufferStep2(BYTE* pRestoredDataBuffer, int nDataLen, int* pnRestoredDataLen)
{
- m_pRestBuffer = (*m_PRestoreBuffer)(pRestoredDataBuffer, nDataLen, pnRestoredDataLen);
+ m_pRestBuffer = (*m_PRestoreBuffer)(&context, pRestoredDataBuffer, nDataLen, pnRestoredDataLen);
//m_RestMutex.unlock();
return NULL;
}
diff -ru3 UltraVnc-101-src/src/ultravnc/DSMPlugin/DSMPlugin.h UltraVnc-101-src.new/src/ultravnc/DSMPlugin/DSMPlugin.h
--- UltraVnc-101-src/src/ultravnc/DSMPlugin/DSMPlugin.h 2005-02-17 22:48:18.000000000 -0600
+++ UltraVnc-101-src.new/src/ultravnc/DSMPlugin/DSMPlugin.h 2005-10-01 07:14:55.015625000 -0500
@@ -43,14 +43,14 @@
// A plugin dll must export the following functions (with same convention)
typedef char* (__cdecl *DESCRIPTION)(void);
-typedef int (__cdecl *STARTUP)(void);
-typedef int (__cdecl *SHUTDOWN)(void);
-typedef int (__cdecl *SETPARAMS)(HWND, char*);
-typedef char* (__cdecl *GETPARAMS)(void);
-typedef BYTE* (__cdecl *TRANSFORMBUFFER)(BYTE*, int, int*);
-typedef BYTE* (__cdecl *RESTOREBUFFER)(BYTE*, int, int*);
-typedef void (__cdecl *FREEBUFFER)(BYTE*);
-typedef int (__cdecl *RESET)(void);
+typedef int (__cdecl *STARTUP)(void**, HINSTANCE);
+typedef int (__cdecl *SHUTDOWN)(void**);
+typedef int (__cdecl *SETPARAMS)(void**,HWND, char*);
+typedef char* (__cdecl *GETPARAMS)(void**);
+typedef BYTE* (__cdecl *TRANSFORMBUFFER)(void**,BYTE*, int, int*);
+typedef BYTE* (__cdecl *RESTOREBUFFER)(void**,BYTE*, int, int*);
+typedef void (__cdecl *FREEBUFFER)(void**,BYTE*);
+typedef int (__cdecl *RESET)(void**);
//
@@ -88,6 +88,8 @@
omni_mutex m_RestMutex;
private:
+ void *context;
+
bool m_fLoaded;
bool m_fEnabled;
diff -ru3 UltraVnc-101-src/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.cpp UltraVnc-101-src.new/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.cpp
--- UltraVnc-101-src/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.cpp 2005-04-16 14:00:56.000000000 -0500
+++ UltraVnc-101-src.new/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.cpp 2005-10-01 07:16:26.640625000 -0500
@@ -46,28 +46,25 @@
//
//////////////////////////////////////////////////////////////////////////////
+#define TESTPLUGIN_EXPORTS
#include "TestPlugin.h"
-HINSTANCE hInstance;
-PLUGINSTRUCT* pPlugin = NULL; // struct (or class instance) that handles all Plugin params.
- // Given as an example.
-
-// Internal Plugin vars, depending on what it does
-char szExternalKey[255]; // To store the password/key transmitted via SetParams() by UltraVNC apps
-char szLoaderType[32]; // To store the type of application that has loaded the plugin
-BYTE* pLocalTransBuffer = NULL; // Local Transformation buffer (freed on VNC demand)
-BYTE* pLocalRestBuffer = NULL; // Local Restoration buffer (freed on VNC demand)
-int nLocalTransBufferSize = 0;
-int nLocalRestBufferSize = 0;
-//
-
+typedef struct {
+ HINSTANCE hInstance;
+ char szExternalKey[255]; // To store the password/key transmitted via SetParams() by UltraVNC apps
+ char szLoaderType[32]; // To store the type of application that has loaded the plugin
+ BYTE* pLocalTransBuffer; // Local Transformation buffer (freed on VNC demand)
+ BYTE* pLocalRestBuffer; // Local Restoration buffer (freed on VNC demand)
+ int nLocalTransBufferSize;
+ int nLocalRestBufferSize;
+} pluginState;
// Plugin Description
// Please use the following format (with ',' (comma) as separator)
// Name-Description,Author,Date,Version,FileName-Comment
// For the version, we recommend the following format: x.y.z
// The other fields (Name-Description, Author, Date, FileName-Comment) are format free (don't use ',' in them, of course)
-#define PLUGIN_DESCRIPTION "TestPlugin,Sam,Nov 21 2002,1.0.0,TestPlugin.dsm"
+#define PLUGIN_DESCRIPTION "TestPlugin,Duff,Oct 01 2005,2.0.0,TestPlugin.dsm"
@@ -95,10 +92,16 @@
// Initialize the plugin and all its internals
// Return -1 if error
//
-TESTPLUGIN_API int Startup(void)
+TESTPLUGIN_API int Startup(void **context, HINSTANCE hInstance)
{
+ *context = (void*)(new pluginState);
+ ((pluginState*)(*context))->pLocalTransBuffer = NULL;
+ ((pluginState*)(*context))->nLocalTransBufferSize = 0;
+ ((pluginState*)(*context))->pLocalRestBuffer = NULL;
+ ((pluginState*)(*context))->nLocalRestBufferSize = 0;
+ ((pluginState*)(*context))->hInstance = hInstance;
// Init everything
- memset(szExternalKey, 0, sizeof(szExternalKey));
+ memset(((pluginState*)(*context))->szExternalKey, 0, sizeof(((pluginState*)(*context))->szExternalKey));
// Create threads if any
return 1;
}
@@ -108,10 +111,12 @@
// Stop and Clean up the plugin
// Return -1 if error
//
-TESTPLUGIN_API int Shutdown(void)
+TESTPLUGIN_API int Shutdown(void **context)
{
// Terminate Threads if any
// Cleanup everything
+ delete ((pluginState*)(*context));
+ *context = NULL;
return 1;
}
@@ -120,11 +125,11 @@
// Stop and Clean up the plugin
// Return -1 if error
//
-TESTPLUGIN_API int Reset(void)
+TESTPLUGIN_API int Reset(void **context)
{
// Reset the plugin (buffers, keys, whatever that
// requires to be reset between 2 connections
-
+ memset(((pluginState*)(*context))->szExternalKey, 0, sizeof(((pluginState*)(*context))->szExternalKey));
return 1;
}
@@ -163,25 +168,25 @@
// (this info can be used for application/environnement dependent
// operations (config saving...))
//
-TESTPLUGIN_API int SetParams(HWND hVNC, char* szParams)
+TESTPLUGIN_API int SetParams(void **context, HWND hVNC, char* szParams)
{
// CASE 1
// Get the environnement (szLoaderType) value that is always sent from
// VNC viewer or server
- MyStrToken(szLoaderType, szParams, 2, ',');
+ MyStrToken(((pluginState*)(*context))->szLoaderType, szParams, 2, ',');
// If hVNC != 0, display for instance the Plugin Config Dialog box
if (hVNC)
{
// Display the Plugin Config dialog box
- DoDialog();
+ DoDialog(context);
}
// CASE 2:
// Use szParams to setup the Plugin.
// In this example Plugin, the externalkey is not used but we store it anyway.for demo.
// (it corresponds to the VNC password as we require it in the GetParams() function below)
- MyStrToken(szExternalKey, szParams, 1, ',');
+ MyStrToken(((pluginState*)(*context))->szExternalKey, szParams, 1, ',');
return 1;
}
@@ -196,13 +201,13 @@
// Thus this function is called once before the SetParams() function is called
// - Return "VNCPasswordNeeded" if VNC password must be transmitted by the UltraVNC app
// - Return any other Plugin parameters value otherwise (not used in WinVNC & vncviewer for now)
-TESTPLUGIN_API char* GetParams(void)
+TESTPLUGIN_API char* GetParams(void **context)
{
- if (strlen(szExternalKey) > 0)
- return szExternalKey; // Return the already stored externalkey params
+ if (strlen(((pluginState*)(*context))->szExternalKey) > 0)
+ return "IveGotAllINeedThanks";
+ // return strlen(((pluginState*)(*context))->szExternalKey); // Return the already stored externalkey params // err... returning an int for a char*?
else
return "VNCPasswordNeeded";
- // return "IveGotAllINeedThanks";
}
//
@@ -212,9 +217,9 @@
// buffer containing the resulting data.
// The length of the resulting data is given by pnTransformedDataLen
//
-TESTPLUGIN_API BYTE* TransformBuffer(BYTE* pDataBuffer, int nDataLen, int* pnTransformedDataLen)
+TESTPLUGIN_API BYTE* TransformBuffer(void **context, BYTE* pDataBuffer, int nDataLen, int* pnTransformedDataLen)
{
- BYTE* pTransBuffer = CheckLocalTransBufferSize(GiveTransDataLen(nDataLen));
+ BYTE* pTransBuffer = CheckLocalTransBufferSize(context, GiveTransDataLen(nDataLen));
if (pTransBuffer == NULL)
{
*pnTransformedDataLen = -1;
@@ -259,7 +264,7 @@
// - Calls RestoreBuffer again to actually restore data into the given destination buffer.
// This way the copies of data buffers are reduced to the minimum.
//
-TESTPLUGIN_API BYTE* RestoreBuffer(BYTE* pRestoredDataBuffer, int nDataLen, int* pnRestoredDataLen)
+TESTPLUGIN_API BYTE* RestoreBuffer(void **context, BYTE* pRestoredDataBuffer, int nDataLen, int* pnRestoredDataLen)
{
// If given buffer is NULL, allocate necessary space here and return the pointer.
// Additionaly, calculate the resulting length based on nDataLen and return it at the same time.
@@ -268,7 +273,7 @@
// Give the size of the transformed data buffer, based on the original data length
*pnRestoredDataLen = GiveTransDataLen(nDataLen);
// Ensure the pLocalRestBuffer that receive transformed data is big enought
- BYTE* pBuffer = CheckLocalRestBufferSize(*pnRestoredDataLen);
+ BYTE* pBuffer = CheckLocalRestBufferSize(context, *pnRestoredDataLen);
return pBuffer; // Actually pBuffer = pLocalRestBuffer
}
@@ -282,13 +287,13 @@
int i;
for (i = 0; i < nDataLen; i++)
{
- pRestoredDataBuffer[i] = pLocalRestBuffer[i];
+ pRestoredDataBuffer[i] = ((pluginState*)(*context))->pLocalRestBuffer[i];
}
// return the resulting data length
*pnRestoredDataLen = GiveRestDataLen(nDataLen);
- return pLocalRestBuffer;
+ return ((pluginState*)(*context))->pLocalRestBuffer;
}
@@ -297,7 +302,7 @@
// in TransformBuffer and RestoreBuffer, using the method adapted
// to the used allocation method.
//
-TESTPLUGIN_API void FreeBuffer(BYTE* pBuffer)
+TESTPLUGIN_API void FreeBuffer(void **context, BYTE* pBuffer)
{
if (pBuffer != NULL)
free(pBuffer);
@@ -350,10 +355,10 @@
//
// Display the Plugin Config Dialog box
//
-int DoDialog(void)
+int DoDialog(void** context)
{
- return DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_CONFIG_DIALOG),
- NULL, (DLGPROC) ConfigDlgProc, (LONG) pPlugin);
+ return DialogBoxParam(((pluginState*)(*context))->hInstance, MAKEINTRESOURCE(IDD_CONFIG_DIALOG),
+ NULL, (DLGPROC) ConfigDlgProc, (LONG) (*context));
}
@@ -362,7 +367,7 @@
//
BOOL CALLBACK ConfigDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
- PLUGINSTRUCT* _this = (PLUGINSTRUCT*) GetWindowLong(hwnd, GWL_USERDATA);
+ pluginState *_this = (pluginState*) GetWindowLong(hwnd, GWL_USERDATA);
switch (uMsg)
{
@@ -460,24 +465,24 @@
// Allocate more space for the local transformation buffer if necessary
// and returns the pointer to this buffer
//
-BYTE* CheckLocalTransBufferSize(int nBufferSize)
+BYTE* CheckLocalTransBufferSize(void** context, int nBufferSize)
{
- if (nLocalTransBufferSize >= nBufferSize) return pLocalTransBuffer;
+ if (((pluginState*)(*context))->nLocalTransBufferSize >= nBufferSize) return ((pluginState*)(*context))->pLocalTransBuffer;
BYTE *pNewBuffer = (BYTE *) malloc (nBufferSize + 256);
if (pNewBuffer == NULL)
{
return NULL;
}
- if (pLocalTransBuffer != NULL)
- free(pLocalTransBuffer);
+ if (((pluginState*)(*context))->pLocalTransBuffer != NULL)
+ free(((pluginState*)(*context))->pLocalTransBuffer);
- pLocalTransBuffer = pNewBuffer;
- nLocalTransBufferSize = nBufferSize + 256;
+ ((pluginState*)(*context))->pLocalTransBuffer = pNewBuffer;
+ ((pluginState*)(*context))->nLocalTransBufferSize = nBufferSize + 256;
- memset(pLocalTransBuffer, 0, nLocalTransBufferSize);
+ memset(((pluginState*)(*context))->pLocalTransBuffer, 0, ((pluginState*)(*context))->nLocalTransBufferSize);
- return pLocalTransBuffer;
+ return ((pluginState*)(*context))->pLocalTransBuffer;
}
@@ -485,24 +490,24 @@
// Allocate more space for the local restoration buffer if necessary
// and returns the pointer to this buffer
//
-BYTE* CheckLocalRestBufferSize(int nBufferSize)
+BYTE* CheckLocalRestBufferSize(void **context, int nBufferSize)
{
- if (nLocalRestBufferSize >= nBufferSize) return pLocalRestBuffer;
+ if (((pluginState*)(*context))->nLocalRestBufferSize >= nBufferSize) return ((pluginState*)(*context))->pLocalRestBuffer;
BYTE *pNewBuffer = (BYTE *) malloc (nBufferSize + 256);
if (pNewBuffer == NULL)
{
return NULL;
}
- if (pLocalRestBuffer != NULL)
- free(pLocalRestBuffer);
+ if (((pluginState*)(*context))->pLocalRestBuffer != NULL)
+ free(((pluginState*)(*context))->pLocalRestBuffer);
- pLocalRestBuffer = pNewBuffer;
- nLocalRestBufferSize = nBufferSize + 256;
+ ((pluginState*)(*context))->pLocalRestBuffer = pNewBuffer;
+ ((pluginState*)(*context))->nLocalRestBufferSize = nBufferSize + 256;
- memset(pLocalRestBuffer, 0, nLocalRestBufferSize);
+ memset(((pluginState*)(*context))->pLocalRestBuffer, 0, ((pluginState*)(*context))->nLocalRestBufferSize);
- return pLocalRestBuffer;
+ return ((pluginState*)(*context))->pLocalRestBuffer;
}
@@ -515,15 +520,6 @@
LPVOID lpReserved
)
{
- switch (dwReason)
- {
- case DLL_PROCESS_ATTACH:
- hInstance = hInst;
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
return TRUE;
}
diff -ru3 UltraVnc-101-src/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.h UltraVnc-101-src.new/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.h
--- UltraVnc-101-src/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.h 2005-04-15 22:27:16.000000000 -0500
+++ UltraVnc-101-src.new/src/ultravnc/DSMPlugin/TestPlugin/TestPlugin.h 2005-10-01 07:14:29.000000000 -0500
@@ -58,6 +58,7 @@
#include "resource.h"
// Plugin struct example - Of course some classes can be used instead...
+#if 0
typedef struct
{
char szDescription[256];
@@ -66,6 +67,7 @@
int nInternalParam2; // And so on.. add what you need.
} PLUGINSTRUCT;
+#endif
//
@@ -74,11 +76,11 @@
BOOL MyStrToken(LPSTR szToken, LPSTR lpString, int nTokenNum, char cSep);
int GiveTransDataLen(int nDataLen);
int GiveRestDataLen(int nDataLen);
-BYTE* CheckLocalTransBufferSize(int nBufferSize);
-BYTE* CheckLocalRestBufferSize(int nBufferSize);
+BYTE* CheckLocalTransBufferSize(void **context, int nBufferSize);
+BYTE* CheckLocalRestBufferSize(void **context, int nBufferSize);
// Config procs if necessary (the plugin is allowed to have no config dialog at all)
BOOL CALLBACK ConfigDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
-int DoDialog(void);
+int DoDialog(void **context);
//
@@ -88,12 +90,12 @@
extern "C"
{
TESTPLUGIN_API char* Description(void);
-TESTPLUGIN_API int Startup(void);
-TESTPLUGIN_API int Shutdown(void);
-TESTPLUGIN_API int Reset(void);
-TESTPLUGIN_API int SetParams(HWND hVNC, char* szParams);
-TESTPLUGIN_API char* GetParams(void);
-TESTPLUGIN_API BYTE* TransformBuffer(BYTE* pDataBuffer, int nDataLen, int* pnTransformedDataLen);
-TESTPLUGIN_API BYTE* RestoreBuffer(BYTE* pTransBuffer, int nTransDataLen, int* pnRestoredDataLen);
-TESTPLUGIN_API void FreeBuffer(BYTE* pBuffer);
+TESTPLUGIN_API int Startup(void** context, HINSTANCE *hInstance);
+TESTPLUGIN_API int Shutdown(void** context);
+TESTPLUGIN_API int Reset(void** context);
+TESTPLUGIN_API int SetParams(void** context, HWND hVNC, char* szParams);
+TESTPLUGIN_API char* GetParams(void** context);
+TESTPLUGIN_API BYTE* TransformBuffer(void** context, BYTE* pDataBuffer, int nDataLen, int* pnTransformedDataLen);
+TESTPLUGIN_API BYTE* RestoreBuffer(void** context, BYTE* pTransBuffer, int nTransDataLen, int* pnRestoredDataLen);
+TESTPLUGIN_API void FreeBuffer(void** context, BYTE* pBuffer);
}