⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sample.cpp

📁 一个OPC服务器开发的源代码。结构清晰
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/**************************************************************************
 *                                                                        *
 * Light OPC Server development library                                   *
 *                                                                        *
 *   Copyright (c) 2000 Timofei Bondarenko                                *
                                                                          *
 Sample server

 NOTE: the sample contains code for both in-proc and out-of-proc 
  servers. Therefore here is some overhead due this.

 NOTE: the exe version of sample can be built for CONSOLE or WINDOWS mode.
 see linker options for subsystem/entrypoint.
 In console mode it will print messages to console window, when invoked
 from command line, and can be terminated by Ctrl^C/Ctrl^Break.
 On another hand, it will display a console window for a short time when
 invoked from a windowed application.
 **************************************************************************/

#define _WIN32_DCOM
#include <windows.h>
#include "unilog.h"
#define LOGID log,0
#include <ole2.h>
#include <olectl.h>
#include <oleauto.h>
#include <process.h>
#include <stdio.h>
#include <errno.h>
#include <locale.h>
#include <opcda.h>
#include <opcerror.h>
#include "lightopc.h"

#if 0
static LONG server_process;
#define CoAddRefServerProcess()  (InterlockedIncrement(&server_process))
#define CoReleaseServerProcess() (InterlockedDecrement(&server_process))
#define CoQueryClientBlanket(a,b,c,d,e,userid,f) (*((const wchar_t**)userid)=L"Wine!")
#endif

unilog *log;                    /* logging entry */
int use_console = 0;
int test_mode = 0;

/********************* OPC vendor info ***************************************/
static const loVendorInfo vendor = {
  3 /*Major */ , 2 /*Minor */ , 1 /*Build */ , 0 /*Reserv */ ,
  "Sample OPC Server #9"
};

loService *my_service;
static int driver_init(int lflags);
static void driver_destroy(void);
static void simulate(unsigned pause);

/* OLE-specefic data: ***********************************************************/

// {C896CBD0-ABF5-11d4-BED0-00002120DB5C}   inproc-server
static const GUID CLSID_LightOPCServerDLL =
  { 0xc896cbd0, 0xabf5, 0x11d4, {0xbe, 0xd0, 0x0, 0x0, 0x21, 0x20, 0xdb,
                                 0x5c} };

// {4EA2713D-CA07-11d4-BEF5-00002120DB5C}   exe-server
static const GUID CLSID_LightOPCServerEXE =
  { 0x4ea2713d, 0xca07, 0x11d4, {0xbe, 0xf5, 0x0, 0x0, 0x21, 0x20, 0xdb,
                                 0x5c} };

/**** Server Counting stuff & OLE ICF implementation *****************************
  The IClassFactory is unavoidable evil. Feel free to go ahead.
  Basically we've to unload when the server_count being zero.
  But there are different techniques for in-/out-of- proc servers.
*/

class myClassFactory: public IClassFactory
{
public:
 int  is_out_of_proc, 
      server_inuse; /* go 0 when unloading initiated */
 LONG server_count;
 CRITICAL_SECTION lk_count;  /* protect server_count */

 myClassFactory(): is_out_of_proc(0), server_inuse(0), server_count(0)
   {
      InitializeCriticalSection(&lk_count);
   }
 ~myClassFactory()
   {
      DeleteCriticalSection(&lk_count);
   }

  void serverAdd(void);
  void serverRemove(void);

/* Do nothing: we're static, he-he */  
  STDMETHODIMP_(ULONG) AddRef(void) { return 1; }
  STDMETHODIMP_(ULONG) Release(void) { return 1; }

  STDMETHODIMP QueryInterface(REFIID iid, LPVOID *ppInterface)
    {
      if (ppInterface == NULL)
        return E_INVALIDARG;
      if (iid == IID_IUnknown || iid == IID_IClassFactory)
        {
          UL_DEBUG((LOGID, "myClassFactory::QueryInterface() Ok"));
          *ppInterface = this;
          AddRef();
          return S_OK;
        }
      UL_DEBUG((LOGID, "myClassFactory::QueryInterface() Failed"));
      *ppInterface = NULL;
      return E_NOINTERFACE;
    }

  STDMETHODIMP LockServer(BOOL fLock)
    {
      UL_DEBUG((LOGID, "myClassFactory::LockServer(%d)", fLock));
      if (fLock) serverAdd();
      else serverRemove();
      return S_OK;
    }

  STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid,
                              LPVOID *ppvObject);

};

static myClassFactory my_CF;

void myClassFactory::serverAdd(void)
{
  EnterCriticalSection(&lk_count);
  if (is_out_of_proc) CoAddRefServerProcess();  
  ++server_count;
  LeaveCriticalSection(&lk_count);
}

void myClassFactory::serverRemove(void)
{
  EnterCriticalSection(&lk_count);
  if (is_out_of_proc)
    {
     if (0 == CoReleaseServerProcess())
       server_inuse = 0;
    }
  if (0 == --server_count && server_inuse) server_inuse = 0;
  LeaveCriticalSection(&lk_count);
}

static void a_server_finished(void *arg, loService *b, loClient *c)
{
  /* ARG is the same as we've passed to loClientCreate() */
  UL_DEBUG((LOGID, "a_server_finished(%lu)...", my_CF.server_count));
  my_CF.serverRemove();

/* OPTIONAL: */
  UL_INFO((LOGID, "a_server_finished(%lu) USERID=<%ls>",
    my_CF.server_count, arg? arg: L"<null>"));
  if (use_console)
    printf("-Detaching a client. USERID: <%ls>\n", arg? arg: L"<null>");
}

static void dll_simulator_wait(void); /* in-proc specefic */
static void dll_simulator_start(void); /* in-proc specefic */

STDMETHODIMP myClassFactory::CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid,
                                            LPVOID *ppvObject)
{
  IUnknown *server = 0;
  HRESULT hr = S_OK;

/* OPTIONAL: security stuff */
  OLECHAR *userid = 0;
  wchar_t *cuserid;
  LONG userno;
  static LONG usercount;

  userno = InterlockedIncrement(&usercount);

  CoQueryClientBlanket(0, 0, 0, 0, 0, (RPC_AUTHZ_HANDLE*)&userid, 0);
  if (!userid) userid = L"{unknown}";

  UL_WARNING((LOGID, "USER:#%ld <%ls>", userno, userid));
  if (use_console)
    printf("+Attaching a client #%ld. USERID: <%ls>\n", usercount, userid);

  if (cuserid = (wchar_t*)malloc((wcslen(userid) + 16) * sizeof(wchar_t)))
    swprintf(cuserid, L"#%ld %ls", userno, userid);
/* -- end of security stuff */

  if (pUnkOuter)
    {
#if 1 /* Do we support aggregation? */
     if (riid != IID_IUnknown) 
#endif
          return CLASS_E_NOAGGREGATION;
    }

  serverAdd();  /* the lock for a_server_finished() */

/***********************************************
 * check other conditions (i.e. security) here *
 ***********************************************/

  if (0 == server_inuse) /* we're stopped */
    {                    /* stopping initiated when there are no active instances */
      if (is_out_of_proc) 
        {                /* a stopped EXE should exit soon and can't work anymore */
          UL_MESSAGE((LOGID, "myClassFactory:: Server already finished"));
          serverRemove();
          return E_FAIL;
        }
      else /* in-proc specefic here: */
        {  /* restart the server if not already running */
          dll_simulator_wait();   /* wait for stopping complete */
          dll_simulator_start();  /* then restart */
          if (0 == server_inuse)  
            {
              UL_MESSAGE((LOGID, "myClassFactory:: Can't start server"));
              serverRemove();
              return E_FAIL;
            }
        }
    }
{
 IUnknown *inner = 0;
 if (loClientCreate_agg(my_service, (loClient**)&server, 
                       pUnkOuter, &inner,
                       0, &vendor, a_server_finished, cuserid/*this*/))
    {
      serverRemove();
      hr = E_OUTOFMEMORY;
      UL_MESSAGE((LOGID, "myClassFactory::loClientCreate_agg() failed"));
    }
  else if (pUnkOuter) *ppvObject = (void*)inner; /*aggregation requested*/
  else /* no aggregation */
    {
/* loClientCreate(my_service, (loClient**)&server, 
                  0, &vendor, a_server_finished, cuserid) - with no aggregation */
      /* Initally the created SERVER has RefCount=1 */
      hr = server->QueryInterface(riid, ppvObject); /* Then 2 (if success) */
      server->Release(); /* Then 1 (on behalf of client) or 0 (if QI failed) */
      if (FAILED(hr)) 
        UL_MESSAGE((LOGID, "myClassFactory::loClient QueryInterface() failed"));
      /* So we shouldn't carry about SERVER destruction at this point */
    }
}
  if (SUCCEEDED(hr))
    {
      loSetState(my_service, (loClient*)server,
             loOP_OPERATE, (int)OPC_STATUS_RUNNING, /* other states are possible */
             "Finished by client");
      UL_DEBUG((LOGID, "myClassFactory::server_count = %ld", server_count));
    }

  return hr;
}

/************************* The END of OLE-specific ***************************/

/****************** The Process Data to be exported via OPC ******************
 (driver's internal representation) */

static CRITICAL_SECTION lk_values;     /* protects ti[] from simultaneous 
                                    access by simulator() and WriteTags() */
/* Our data tags: */
/* zero is resierved for an invalid RealTag */
#define TI_zuzu      (1)
#define TI_lulu      (2)
#define TI_bandwidth (3)
#define TI_array     (4)
#define TI_enum      (5)
#define TI_quiet     (6)
#define TI_quality   (7)
#define TI_string    (8)
#define TI_MAX       (8)

static loTagId ti[TI_MAX + 1];          /* their IDs */
static const char *tn[TI_MAX + 1] =     /* their names */
{ "--not--used--", "zuzu", "lulu", "bandwidth", "array", "enum-localizable",
    "quiet", "quality", "string" };
static loTagValue tv[TI_MAX + 1];       /* their values */


/**********************************************************************
 sample server initiation & simulation
 **********************************************************************/

/* OPTIONAL: show client's interests */

void activation_monitor(const loCaller *ca, int count, loTagPair *til)
{
  int act = 1;
  if (0 > count)
    act = 0, count = -count;
  while(count--)
    {
      UL_DEBUG((LOGID, "MON: %u %s %s", til[count].tpTi,
                tn[(int) til[count].tpRt], act ? "On" : "Off"));
    }
}


/* OPTIONAL: write back to the device */

int WriteTags(const loCaller *ca,
              unsigned count, loTagPair taglist[],
              VARIANT values[], HRESULT error[], HRESULT *master, LCID lcid)
{
  unsigned ii;
  UL_TRACE((LOGID, "WriteTags(%x) invoked"));

  EnterCriticalSection(&lk_values);

  for(ii = 0; ii < count; ii++)
    {
      HRESULT hr = S_OK;
      loTagId clean = 0;

      switch((int)taglist[ii].tpRt)
        {
      case TI_zuzu:
        { double oldval = tv[TI_zuzu].tvValue.dblVal;
        hr = VariantChangeType(&tv[TI_zuzu].tvValue,
                               &values[ii], 0, V_VT(&tv[TI_zuzu].tvValue));
        UL_INFO((LOGID, "%p:%s:WriteTags(zuzu) = %.1f old=%.1f [%x]", 
            ca->ca_cli, loClientName(ca->ca_cli),
          tv[TI_zuzu].tvValue.dblVal, oldval, hr));        
        if (tv[TI_zuzu].tvValue.dblVal < 0)
          hr = DISP_E_TYPEMISMATCH; /* simulate a write error */
        }
        break;

      case TI_lulu:
        hr = VariantChangeType(&tv[TI_lulu].tvValue, &values[ii], 0, VT_I2);
        if (S_OK == hr)
          lo_statperiod(V_I2(&tv[TI_lulu].tvValue)); /* VERY OPTIONAL, really */
          /* The splining factor for bandwidth calculations/trending */
        break;

      case TI_quiet:
        hr = VariantChangeType(&tv[TI_quiet].tvValue, &values[ii], 0, 
                          V_VT(&tv[TI_quiet].tvValue));
        break;

      case TI_array:
        hr = lo_variant_changetype_array(&tv[TI_array].tvValue,
                                 &values[ii], lcid, 0, 
                                 V_VT(&tv[TI_array].tvValue));
        break;

      case 0:  /* ignore */
      default: /* preserve unhandled tags */
        clean = taglist[ii].tpTi;
        break;
        }
      if (S_OK != hr) 
        {
          *master = S_FALSE;
          error[ii] = hr;

          UL_TRACE((LOGID, "%!l WriteTags(Rt=%u Ti=%u %s)", 
              hr, taglist[ii].tpRt, taglist[ii].tpTi, 
              tn[(int)taglist[ii].tpRt <= TI_MAX? (int)taglist[ii].tpRt: 0]));
        }
      taglist[ii].tpTi = clean; /* clean if ok */
    }

  LeaveCriticalSection(&lk_values);

  return loDW_TOCACHE; /* put to the cache all tags unhandled here */
   // loDW_ALLDONE; 
}

/* OPTIONAL: example of non-trivial datatype conversion */

static void local_text(WCHAR buf[32], unsigned nn, LCID lcid);

void ConvertTags(const loCaller *ca,
                 unsigned count, const loTagPair taglist[],
                 VARIANT *values, WORD *qualities, HRESULT *errs,
                 HRESULT *master_err, HRESULT *master_qual,
                 const VARIANT src[], const VARTYPE vtypes[], LCID lcid)
{
  unsigned ii;

  for(ii = 0; ii < count; ii++)
    {
      HRESULT hr = S_OK;
      VARTYPE reqtype = vtypes[ii];
      if (reqtype == VT_EMPTY) reqtype = V_VT(&src[ii]);

      switch((int)taglist[ii].tpRt)
        {
      case 0: /* ignore */
        break;

      case TI_array:
        if (V_VT(&src[ii]) == reqtype)
          {
            hr = values == src? S_OK : VariantCopy(&values[ii], (VARIANT*)&src[ii]);
          }
        else 
          { 
            hr = lo_variant_changetype_array(&values[ii], 
                    (VARIANT*)&src[ii], lcid, 0, reqtype);
          }
        break;

      case TI_enum:
        if (V_VT(&src[ii]) == VT_I2 && reqtype == VT_BSTR)
          {
            WCHAR ww[32];
            int vv = V_I2(&src[ii]);
            VariantClear(&values[ii]);
            local_text(ww, vv, lcid);
            if (V_BSTR(&values[ii]) = SysAllocString(ww))
              V_VT(&values[ii]) = VT_BSTR;
            else hr = E_OUTOFMEMORY;
            break;
          }

      default:
        if (reqtype == V_VT(&src[ii]))
          {
            if (values == src) hr = S_OK;
            else hr = VariantCopy(values + ii, (VARIANT*)&src[ii]);
          }
        else
          hr = VariantChangeType(values + ii, (VARIANT*)&src[ii], 0, reqtype);

        UL_ERROR((LOGID, "ConvII NotRequested(%u %u)[%u/%u]", 
          taglist[ii].tpRt, taglist[ii].tpTi, ii, count));
        break;
        } /* end of switch( */

      if (S_OK != hr)
        {
          errs[ii] = hr;
          qualities[ii] = OPC_QUALITY_BAD;
          *master_err = *master_qual = S_FALSE;

          UL_WARNING((LOGID, "%!l ConvII Error(Rt=%u Ti=%u %s)[%u/%u]", 
              hr, taglist[ii].tpRt, taglist[ii].tpTi, 
              tn[(int)taglist[ii].tpRt <= TI_MAX? (int)taglist[ii].tpRt: 0],
              ii, count));
        }
    } /* end of for(...*/
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -