📄 sample.cpp
字号:
static const unsigned char legalq[] = {
OPC_QUALITY_CONFIG_ERROR , OPC_QUALITY_NOT_CONNECTED ,
OPC_QUALITY_DEVICE_FAILURE , OPC_QUALITY_SENSOR_FAILURE ,
OPC_QUALITY_LAST_KNOWN , OPC_QUALITY_COMM_FAILURE ,
OPC_QUALITY_OUT_OF_SERVICE ,
// STATUS_MASK Values for Quality = UNCERTAIN
OPC_QUALITY_LAST_USABLE , OPC_QUALITY_SENSOR_CAL ,
OPC_QUALITY_EGU_EXCEEDED , OPC_QUALITY_SUB_NORMAL ,
// STATUS_MASK Values for Quality = GOOD
OPC_QUALITY_LOCAL_OVERRIDE };
tv[TI_quality].tvState.tsTime = ft;
tv[TI_quality].tvState.tsQuality =
legalq[((unsigned)ft.dwLowDateTime >> 24) % SIZEOF_ARRAY(legalq)];
/** OPTIONAL: change the STRING variable: */
WCHAR wstr[32];
local_text(wstr, (ft.dwLowDateTime >> 24) % 7, 0);
VariantClear(&tv[TI_string].tvValue); /* don't miss it!
BSTR is not a simple type */
V_BSTR(&tv[TI_string].tvValue) = SysAllocString(wstr);
V_VT(&tv[TI_string].tvValue) = VT_BSTR;
tv[TI_string].tvState.tsTime = ft;
/** OPTIONAL: change the ARRAY variable: */
if (ti[TI_array]) /* has been successfuly initialized? */
{
long ix0 = 1, val = (long)zuzu;
SafeArrayPutElement(V_ARRAY(&tv[TI_array].tvValue), &ix0, &val);
tv[TI_array].tvTi = ti[TI_array];
tv[TI_array].tvState.tsTime = ft;
}
/** MANDATORY: send all the values into the cache: */
loCacheUpdate(my_service, TI_MAX, tv + 1, 0);
LeaveCriticalSection(&lk_values);
if (pause)
{
/* IMPORTANT: force unloading of an out-of-proc
if not connected during PAUSE millisec */
unsigned tnow = GetTickCount();
if (tnow - starttime >= pause)
{
pause = 0;
my_CF.serverRemove();
}
}
if (test_mode)
{
/* OPTIONAL: simulate client's connections to test loSetState
and track down resource leakage */
static int xx;
static IUnknown *cli;
unsigned tnow = GetTickCount();
if (tnow - starttime >= 2500)
{
starttime = tnow;
/* To test for unreleased handles / threads
run taskmgr and see what's happen...*/
if (cli)
{
cli->Release(); cli = 0;
if (5 < ++xx)
{
puts("SHUTDOWN initiated...");
loSetState(my_service, 0, loOP_SHUTDOWN,
OPC_STATUS_SUSPENDED, "forced shutdown");
my_CF.serverRemove();
test_mode = 2;
}
}
else if (test_mode == 1)
{
my_CF.CreateInstance(0, IID_IUnknown, (void **)&cli);
}
else
{
puts("DISCONNECT initiated...");
loSetState(my_service, 0, loOP_STOP | loOP_DISCONNECT,
OPC_STATUS_SUSPENDED, "forced shutdown");
}
}
} /* end of if (test_mode... */
} /* end of loop */
if (0 == my_CF.is_out_of_proc) /* For in-proc servers only! */
{
EnterCriticalSection(&my_CF.lk_count);
driver_destroy();
LeaveCriticalSection(&my_CF.lk_count);
}
UL_MESSAGE((LOGID, "All clean. exiting..."));
}
/***************************************************************************
EXE-specefic stuff
***************************************************************************/
const char eClsidName[] = "LightOPC Sample server (exe)";
const char eProgID[] = "OPC.LightOPC-exe";
HMODULE server_module = 0;
static int mymine(HINSTANCE hInstance, int argc, char *argv[]);
extern "C"
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
static char *argv[3] = { "fake.exe", NULL, NULL };
argv[1] = lpCmdLine;
return mymine(hInstance, 2, argv);
}
extern "C" int main(int argc, char *argv[])
{
return mymine(GetModuleHandle(NULL), argc, argv);
}
int mymine(HINSTANCE hInstance, int argc, char *argv[])
{
int main_rc = 0;
DWORD objid;
int daemon = 0, pause = 20;
const char *exit_msg = "Exiting...";
server_module = hInstance;
log = unilog_Create("LOPC-exe", "|LOPC-exe", "%!T", -1, /* Max filesize: -1 unlimited, -2 -don't change */
ll_MESSAGE); /* level [ll_FATAL...ll_DEBUG] */
unilog_Redirect("LOPC-exe", "LightOPC", 0);
unilog_Delete(log);
log = unilog_Create("Lopc-Sample-exe", "|Lopc-Sample-exe", "", -1, /* Max filesize: -1 unlimited, -2 -don't change */
ll_TRACE); /* level [ll_FATAL...ll_DEBUG] */
UL_DEBUG((LOGID, "WinMain(%s) invoked...", argv[0]));
if (argv[1])
{
printf("%s\nClass %s : ", argv[0], eProgID);
if (strstr(argv[1], "/r"))
{
char np[FILENAME_MAX + 32];
printf("Registering");
GetModuleFileName(NULL, np + 1, sizeof(np) - 8);
np[0] = '"'; strcat(np, "\"");
if (strstr(argv[1], "/r")[2] == 'c') strcat(np, " /c");
if (loServerRegister(&CLSID_LightOPCServerEXE,
eProgID, eClsidName, np, 0))
{
UL_ERROR((LOGID, "%!L Reg <%s> <%s> Failed", eProgID, argv[0]));
puts(" FAILED");
main_rc = 1;
}
else
{
UL_INFO((LOGID, "Reg <%s> <%s> Ok", eProgID, argv[0]));
puts(" Succeeded");
}
goto Finish;
}
else if (strstr(argv[1], "/u"))
{
printf("UnRegistering");
if (loServerUnregister(&CLSID_LightOPCServerEXE, eProgID))
{
UL_WARNING((LOGID, "%!L UnReg <%s> <%s> Failed", eProgID, argv[0]));
puts(" FAILED");
main_rc = 1;
}
else
{
UL_DEBUG((LOGID, "UnReg <%s> <%s> Ok", eProgID, argv[0]));
puts(" Success");
}
goto Finish;
}
else if (strstr(argv[1], "/c") || strstr(argv[1], "/C"))
{
UL_MESSAGE((LOGID, "Creating new console..."));
use_console = 1;
AllocConsole();
goto Cont;
}
else if (strstr(argv[1], "/daemon"))
{
UL_MESSAGE((LOGID, "Running as DAEMON"));
puts("Running as DAEMON...");
daemon = 1; use_console = 1;
goto Cont;
}
else if (strstr(argv[1], "/detach"))
{
UL_MESSAGE((LOGID, "Running as Detached DAEMON"));
puts("Running as Detached DAEMON...");
daemon = 2;
goto Cont;
}
else if (strstr(argv[1], "/test"))
{
UL_MESSAGE((LOGID, "Running in TEST mode"));
puts("Running in TEST mode...");
daemon = 1; use_console = 1; test_mode = 1;
goto Cont;
}
else
{
UL_WARNING((LOGID, "unknown option <%s>", argv[1]));
printf("Unknown option <%s>", argv[1]);
puts("\nOne of following flags can be specified:"
"\n\t/r - register;"
"\n\t/u - unregister;"
"\n\t/rc - register to start with /c key;"
"\n\t/c - create console window;"
"\n\t/daemon - run in daemon mode;"
"\n\t/test - run in test mode for 25 seconds;"
"\n\t/detach - run in unbreakable daemon mode.");
goto Cont;
}
goto Finish;
}
Cont: /* Attempt to start the server */
if (1 != daemon && 0 == use_console)
FreeConsole();
my_CF.is_out_of_proc = my_CF.server_inuse = 1;
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED)))
{
exit_msg = "CoInitializeEx() failed. Exiting...";
UL_ERROR((LOGID, exit_msg));
goto Finish;
}
pause = 20; /* 20 sec can be too short for remote connections */
if (use_console && !daemon)
printf("Waiting %d seconds for connection...\n", pause);
if (driver_init(0))
{
exit_msg = "driver_init() failed. Exiting...";
UL_ERROR((LOGID, exit_msg));
}
else if (FAILED(CoRegisterClassObject(CLSID_LightOPCServerEXE, &my_CF,
CLSCTX_LOCAL_SERVER |
CLSCTX_REMOTE_SERVER |
CLSCTX_INPROC_SERVER,
REGCLS_MULTIPLEUSE, &objid)))
{
exit_msg = "CoRegisterClassObject() failed. Exiting...";
UL_ERROR((LOGID, exit_msg));
}
else
{
if (daemon) pause = 0; // infinite
my_CF.serverAdd(); /* Oops. This will prewent our server from unloading
till PAUSE elapsed and simulate() do my_CF.serverRemove() */
/* STARTing the simulator */
simulate(pause * 1000); /* sec -> millisec; */
/* FINISHED */
if (FAILED(CoRevokeClassObject(objid)))
UL_WARNING((LOGID, "CoRevokeClassObject() failed..."));
}
driver_destroy();
CoUninitialize();
Finish:
if (use_console) puts(exit_msg);
UL_DEBUG((LOGID, "WinMain(%s) finished", argv[0]));
unilog_Delete(log);
log = 0;
return main_rc;
}
/***************************************************************************
DLL-specefic stuff
***************************************************************************/
static void dll_simulator_wait(void) /* in-proc specefic */
{
for(;;)
{
int finished;
EnterCriticalSection(&my_CF.lk_count);
finished = my_service == 0 || my_CF.server_inuse;
LeaveCriticalSection(&my_CF.lk_count);
if (finished) break;
else Sleep(500);
}
/* Looking for conditional variables?
See unilog/condsb.[hc] */
}
static void dll_simulator_start(void) /* in-proc specefic */
{
int rv;
EnterCriticalSection(&my_CF.lk_count);
if (!my_service)
{
if (rv = driver_init( /* inproc only options! */
#if 1
loDf_FREEMARSH | loDf_BOTHMODEL
#else
0
#endif
))
{
UL_ERROR((LOGID, "!%e driver_init FAILED:", rv));
}
else if (-1 == (int)_beginthread((void(*)(void *))simulate, 0, (void *)0))
{
UL_ERROR((LOGID, "!%E _beginthread() FAILED:"));
driver_destroy();
}
else my_CF.server_inuse = 1;
}
LeaveCriticalSection(&my_CF.lk_count);
}
extern "C"
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
if (fdwReason == DLL_PROCESS_ATTACH)
{
server_module = hinstDLL;
log = unilog_Create("LOPC-dll", "|LOPC-dll", "%!T", -1, /* Max filesize: -1 unlimited, -2 -don't change */
ll_DEBUG); /* level [ll_FATAL...ll_DEBUG] */
unilog_Redirect("LOPC-dll", "LightOPC", 0);
unilog_Delete(log);
log = unilog_Create("Lopc-Sample-dll", "|Lopc-Sample-dll", "", -1, /* Max filesize: -1 unlimited, -2 -don't change */
ll_DEBUG); /* level [ll_FATAL...ll_DEBUG] */
UL_DEBUG((LOGID, "DllMAin(process_attach)"));
//driver_init(); /* not the best place */
}
else if (fdwReason == DLL_PROCESS_DETACH)
{
UL_DEBUG((LOGID, "DllMAin(process_detach)"));
unilog_Delete(log);
log = 0;
//driver_destroy(); /* not the best place */
}
return TRUE;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
{
UL_DEBUG((LOGID, "DllGetClassObject() ..."));
if (rclsid == CLSID_LightOPCServerDLL || rclsid == CLSID_LightOPCServerEXE)
{
HRESULT hr = my_CF.QueryInterface(riid, ppv);
UL_DEBUG((LOGID, "%!l DllGetClassObject() >>%04X %s", hr, hr,
FAILED(hr) ? "failed" : "Ok"));
return hr;
}
UL_DEBUG((LOGID, "DllGetClassObject() >>CLASS_E_CLASSNOTAVAILABLE"));
return CLASS_E_CLASSNOTAVAILABLE;
}
STDAPI DllCanUnloadNow(void)
{
UL_DEBUG((LOGID, "DllCanUnloadNow() invoked servers=%d", my_CF.server_count));
my_CF.serverAdd();
my_CF.serverRemove(); /* Force stopping the simulator if not used */
/* the simulator can be restarted in ICF::CreateInstance() if requested */
if (0 == my_CF.server_inuse)
{
dll_simulator_wait();
if (0 == my_CF.server_inuse) return S_OK;
}
return S_FALSE;
}
/* standard OLE registration stuff */
const char dClsidName[] = "LightOPC Sample server (dll)";
const char dProgID[] = "OPC.LightOPC-dll";
STDAPI DllRegisterServer(void)
{
char sFile[FILENAME_MAX + 16];
GetModuleFileName(server_module, sFile, sizeof(sFile) - 1);
UL_DEBUG((LOGID, "DllRegister(%s)", sFile));
return loServerRegister(&CLSID_LightOPCServerDLL, dProgID, dClsidName, sFile,
"Both") ? SELFREG_E_CLASS: S_OK;
}
STDAPI DllUnregisterServer(void)
{
return loServerUnregister(&CLSID_LightOPCServerDLL, dProgID)? SELFREG_E_CLASS: S_OK;
}
/* OPTIONAL: **************** special helpers ******************************/
static void local_text(WCHAR buf[32], unsigned nn, LCID lcid)
{
char sbt[40];
long lcp = CP_ACP;
unsigned nx;
nn %= 7;
/* Nasty Win95 doesn't have proper unicode support.
So we getting singlebyte strings and then converting them to unicode.
But we've to know the right codepage first!
CP_ACP is our cp. An OPC client may choose other. */
if (0 == GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE, sbt, sizeof(sbt)-1))
goto Failure;
lcp = strtoul(sbt, 0, 10);
/* How does called "Monday"+nn in LCID country? */
if (0 == GetLocaleInfoA(lcid, LOCALE_SDAYNAME1 + nn, sbt, sizeof(sbt) - 1))
goto Failure;
nx = strlen(sbt);
if (sizeof(sbt) - nx > 12)
{
sbt[nx++] = ' '; /* Append language name [OPTIONAL] */
if (0 == GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE, sbt + nx,
sizeof(sbt) - nx - 1) &&
0 == GetLocaleInfoA(lcid, LOCALE_SENGCOUNTRY, sbt + nx,
sizeof(sbt) - nx - 1) )
sbt[--nx] = 0; /* ... or the country name */
}
if (0 == MultiByteToWideChar(lcp, 0, sbt, -1, buf, 32))
{
Failure:
swprintf(buf, L"%d [string]", nn);
}
// UL_DEBUG((LOGID, "locals lcid:%x cp:%d [%s] [%ls]%d",
//lcid, lcp, sbt, buf, wcslen(buf)));
}
/******************* This is the end... ************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -