Problem Overview
When executing SQL Server stored procedures from a WinCC C script using ADODB.Command, the runtime returns the error "property ActiveConnection not available". The same block compiles without warnings, the ADODB.Connection object opens cleanly against the connection string, and the stored procedure exists and is executable from SQL Server Management Studio. The failure occurs on the line:
cmd->ActiveConnection = cn;
This error is specific to the WinCC V7.x / WinCC Professional scripting host and its implementation of the __object pointer wrapper around COM. It does not appear in standalone C/C++ programs that use the native Microsoft ADODB headers, and it is independent of the SQL Server instance being targeted. The error means the COM dispatch interface exposed by cmd does not expose the ActiveConnection property at the IDispatch level, so the late-bound put_ActiveConnection call cannot resolve a property DISPID.
ActiveConnection; cn->Open(...) returns without error; GetLastError() in the WinCC diagnostics window reports COM error 0x80020006 (DISP_E_UNKNOWNNAME) or 0x80004002 (E_NOINTERFACE) depending on the script host build.
Root Cause Analysis
The __object type used by the WinCC C interpreter is a thin wrapper that resolves COM properties by name through the type library that was loaded at object creation. Three underlying conditions trigger this error:
-
Type library not loaded for the
Commandobject. When__object_create("ADODB.Command")executes, the script host must loadmsado15.dlland bind its type information. If the host is configured to suppress late binding for objects other thanConnectionandRecordSet, theCommandinterface falls back toIUnknown, andActiveConnectioncannot be resolved by name. -
Connection not opened before assignment. Although the user's code opens the connection, an exception in
cn->Open(...)(for example, an ODBC driver mismatch, a 32-bit/64-bit mismatch, or an authentication failure) leaves the connection in a closed state. Assigning it toActiveConnectionthen triggers the unknown-name error because the command object's dispatch interface rejects the property write. - Mixed-mode COM apartment mismatch. WinCC C scripts execute in the WinCC process under STA threading. If the connection string points to a driver that forces MTA (for example, the SQL Server Native Client 11 under certain build configurations), the cross-apartment marshaling fails and the property setter is never invoked, surfacing as the same error string.
All three causes are addressable from inside the C script without changing the SQL Server side. The corrections below apply to WinCC V7.4 SP1 Update 5 and later through V7.5 SP2 Update 4, as well as WinCC Professional V16 / V17 / V18 in TIA Portal.
Environment and Prerequisites
| Component | Requirement |
|---|---|
| WinCC version | V7.4 SP1 Update 5 or later; or WinCC Professional V16+ in TIA Portal |
| Script host | Global C script action (not project-modifying action); triggers must include the polling cycle that fires the action |
| SQL Server | SQL Server 2012 SP4 or later; Express, Standard, or Enterprise edition acceptable |
| ODBC / OLE DB driver |
MSOLEDBSQL (recommended) or SQLNCLI11; the deprecated SQLOLEDB provider must not be used on SQL Server 2017+ |
| Connection string |
Provider=MSOLEDBSQL;Server=<host>\<instance>;Database=<db>;Trusted_Connection=yes; or with UID/PWD |
| Stored procedure | Created in the target database; GRANT EXECUTE on the procedure to the WinCC runtime service account |
| Firewall | TCP 1433 (default instance) or the dynamic port used by the named instance, open between the WinCC station and the SQL Server |
Verify prerequisites from the WinCC station before authoring the script:
-- From an elevated cmd on the WinCC station
sqlcmd -S SERVER\INSTANCE -d MyDb -Q "SELECT @@VERSION"
If sqlcmd connects, the WinCC service account will also connect provided it has CONNECT SQL on the server and EXECUTE on the target procedure.
Corrected C Script Implementation
The corrected code below resolves the ActiveConnection error by (a) initializing COM on the calling thread, (b) verifying the connection is open before assignment, and (c) using the named Parameters.Refresh followed by direct index assignment, which is the pattern documented for late-bound ADODB.Command in the WinCC scripting reference.
__object *cn = NULL;
__object *rs = NULL;
__object *cmd = NULL;
__object *pms = NULL;
char szError[512];
long lResult = 0;
// 1. Initialize COM on the script thread (STA).
// Required because WinCC C scripts can be scheduled on worker threads.
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
// 2. Create the ADODB objects through the WinCC object factory.
cn = __object_create("ADODB.Connection");
cmd = __object_create("ADODB.Command");
if (cn == NULL || cmd == NULL) {
printf("ADODB object creation failed\n");
goto cleanup;
}
// 3. Build the connection string.
// Use MSOLEDBSQL for SQL Server 2012+ (SQL Server 2017+ recommended).
char szConn[512];
sprintf(szConn,
"Provider=MSOLEDBSQL;Server=%s\\%s;Database=%s;UID=%s;PWD=%s;",
gl_SqlServer, gl_SqlInstance, gl_SqlDatabase,
gl_SqlUser, gl_SqlPassword);
// 4. Open the connection with explicit timeout.
cn->ConnectionTimeout = 15;
cn->CommandTimeout = 30;
lResult = cn->Open(szConn);
if (lResult != 0) {
__object_get_ErrorText(cn, szError, sizeof(szError));
printf("Open failed: %s\n", szError);
goto cleanup;
}
// 5. Assign the connection to the command. This is the line that failed
// in the original code. The key is that the Connection object must be
// open AND in the same COM apartment. Setting it BEFORE the CommandText
// allows the type library to bind ActiveConnection.
cmd->ActiveConnection = cn;
cmd->CommandType = 4; // adCmdStoredProc
cmd->CommandText = "dbo.usp_GetOrderStatus";
cmd->CommandTimeout = 30;
// 6. Append input parameters.
pms = cmd->Parameters;
pms->Refresh();
pms->Append(pms->CreateParameter("@OrderID", 3, 1, 0, lOrderID)); // adInteger, adParamInput
// 7. Execute and capture the recordset.
rs = cmd->Execute(NULL, NULL, 0x00000080 /*adCmdStoredProc*/);
// 8. Read rows.
while (!rs->EOF) {
long lOrderNo = rs->Fields->Item["OrderNo"]->Value;
char szStatus[64];
strcpy(szStatus, (char*)rs->Fields->Item["Status"]->Value);
// ... pass to tag / archive ...
rs->MoveNext();
}
cleanup:
if (rs != NULL) { rs->Close(); rs = NULL; }
if (cn != NULL) { cn->Close(); cn = NULL; }
CoUninitialize();
Why the Original Code Failed
The original snippet set cmd->ActiveConnection = cn directly after creating both objects but did not explicitly verify that cn->Open() succeeded. In the WinCC C scripting host, the return value of a method that returns HRESULT is exposed as a long; failing to check it masks a closed-connection state. The script host then evaluates the property name ActiveConnection against the type library loaded at __object_create("ADODB.Command"). Because the Command object's ActiveConnection setter requires an open Connection argument, the runtime short-circuits to DISP_E_UNKNOWNNAME and surfaces the user-visible message "property ActiveConnection not available".
Two further corrections in the snippet above are critical for production scripts:
-
COM initialization.
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)must be paired withCoUninitialize()at script exit. WinCC C actions do not initialize COM on the calling thread by default; this omission alone accounts for the variant of the error reported on WinCC V7.4 SP1 Update 1 and earlier. -
Connection lifetime. Reusing a single
Connectionacross manyCommandobjects is more efficient and avoids the property-not-available error when the connection is opened inside the same scope as the command.
Parameterized Stored Procedures
SQL Server stored procedures are invoked with the EXECUTE (Transact-SQL) statement. When ADODB sends a parameterized call, it generates EXEC dbo.usp_GetOrderStatus @OrderID = ? on the wire. The Parameters collection must match the procedure's signature, including output parameters and the return value.
| ADO parameter constant | Value | Meaning |
|---|---|---|
adParamInput |
1 | Input parameter |
adParamOutput |
2 | Output parameter |
adParamInputOutput |
3 | Input/output parameter |
adParamReturnValue |
4 | Stored procedure return value |
To capture the return value, append a return-value parameter before calling Execute:
__object *pRet = pms->Append(pms->CreateParameter("@RETURN_VALUE", 3, 4, 0, 0));
cmd->Execute(NULL, NULL, 0x80);
long lRC = pRet->Value;
Note that adCmdStoredProc is 0x00000080 in the CommandTypeEnum. Combining it with the adCmdStoredProc argument to Execute ensures SQL Server parses the procedure body once and reuses the cached plan on subsequent calls.
VBScript Alternative in WinCC
If the C script approach is unstable in a given runtime, WinCC also supports VBScript actions with full ADODB access. The VBScript host binds the type library automatically, so ActiveConnection is resolved without the __object wrapper.
Dim cn, cmd, rs, pms
Set cn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")
cn.ConnectionTimeout = 15
cn.CommandTimeout = 30
cn.Open "Provider=MSOLEDBSQL;Server=SVR1\INST1;Database=Plant;UID=wincc;PWD=secret;"
Set cmd.ActiveConnection = cn
cmd.CommandType = 4 ' adCmdStoredProc
cmd.CommandText = "dbo.usp_GetOrderStatus"
cmd.CommandTimeout = 30
Set pms = cmd.Parameters
pms.Refresh
pms.Append pms.CreateParameter("@OrderID", 3, 1, 0, lOrderID)
Set rs = cmd.Execute
Do While Not rs.EOF
' ... read fields ...
rs.MoveNext
Loop
rs.Close: cn.Close
Set rs = Nothing: Set cn = Nothing
VBScript is generally more forgiving with COM lifetime and apartment issues. Choose VBScript when the C script host is not behaving as expected, when the procedure returns a large RecordSet that benefits from late binding, or when the maintainer is more comfortable with VBScript syntax.
Database Connection Configuration
For repeat connections across many script actions, define the connection string once as a WinCC project property and reference it from the script. In WinCC V7.5 this is configured under Computer Properties > Tags > Internal Tags; in WinCC Professional (TIA Portal) it is a project-wide constant set under Runtime Settings > Scripts > Compiler Constants.
- Open WinCC Explorer > Computer Properties > Startup.
- On the Runtime tab, add the SQL Server OLE DB provider to the list of installed providers;
MSOLEDBSQLregisters itself when its installer runs on the WinCC station. - Define
gl_ConnectionStringas a global C variable in Global Script > C-Editor > Project Functions, declared asextern char* gl_ConnectionStringand assigned in the startup action:
// Project function: InitDatabase()
void InitDatabase() {
sprintf(gl_ConnectionString,
"Provider=MSOLEDBSQL;Server=%s\\%s;Database=%s;UID=%s;PWD=%s;",
GetTagChar("@SQLServer"),
GetTagChar("@SQLInstance"),
GetTagChar("@SQLDatabase"),
GetTagChar("@SQLUser"),
GetTagChar("@SQLPassword"));
}
Error Code Reference
| HRESULT | Symbol | Meaning in this context |
|---|---|---|
| 0x80020006 | DISP_E_UNKNOWNNAME | The dispatch interface does not expose ActiveConnection; the typical WinCC manifestation of the error in the field report. |
| 0x80004002 | E_NOINTERFACE | COM apartment mismatch; the connection cannot be marshaled to the command's apartment. |
| 0x80004005 | E_FAIL | Underlying provider failure; check Connection.Errors collection. |
| 0x800A0E7A | ADODB.Error | Provider cannot locate the stored procedure; verify schema-qualified name and case sensitivity of the collation. |
| 0x800A0E78 | ADODB.Error | Operation canceled by CommandTimeout; increase timeout or optimize the procedure. |
Capture these in the script with __object_get_ErrorText(cn, szError, sizeof(szError)) and __object_get_ErrorText(cmd, szError, sizeof(szError)) immediately after the failure, before any subsequent call resets the error collection.
Verification and Commissioning
After deploying the corrected script, validate with the following sequence:
- Static check. Compile the action in the C editor; the WinCC script compiler must report zero errors and zero warnings. A warning of type "implicit conversion of long to HRESULT" indicates a missing return-code check on an ADODB method.
- Single-step in simulator. Run WinCC Runtime in simulation mode and trigger the action manually. Confirm the diagnostics window shows "Open succeeded" and "Execute returned rows = N".
-
SQL Server trace. Start SQL Server Profiler or an Extended Events session on the server, filter on the
wincclogin, and verify the RPC:Completed event forusp_GetOrderStatuswith the expected parameter values and a duration under theCommandTimeout. -
Tag write-back. Confirm that the values read from the
RecordSetare written to internal tags and that the change is visible on the WinCC screen. An internal tag configured with a linear scaling must be checked separately because raw values are not directly displayed. -
Load test. Drive the action at the expected polling rate for 10 minutes and monitor
cn->State. If the state drifts toadStateClosed, the connection is being torn down by a WinCC project reactivation; move the connection initialization to a startup action and store the pointer as a project-global__object*.
Troubleshooting Matrix
| Symptom | Likely cause | Resolution |
|---|---|---|
property ActiveConnection not available on assignment |
COM not initialized on the script thread | Call CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) at action start |
| Same error after COM init | Connection closed when Open() failed silently |
Check return value of Open() and read Connection.Error collection |
| Error appears only on WinCC restart | Connection pointer not preserved across project reactivation | Initialize connection in Startup action, store pointer as __object* project global |
| Works on WinCC station, fails when WinCC runs as a service | Service account lacks CONNECT SQL
|
Grant CONNECT SQL and EXECUTE on the procedure to the WinCC service account |
| Works in script editor, fails in runtime | Driver mismatch between editor's 32-bit ADO and runtime's 64-bit ADO | Match the WinCC build (32 or 64 bit) with the OLE DB provider; install both MSOLEDBSQL x86 and x64 if both builds are used |
| Procedure runs but no rows returned | Parameter not bound correctly; Parameters.Refresh missing |
Call Refresh() after setting CommandText and before Append
|
adCmdStoredProc ignored; ad-hoc SQL executed |
CommandType set after ActiveConnection in original code |
Set ActiveConnection first, then CommandType, then CommandText
|
Field Notes
- The
__objectwrapper in WinCC C is case-sensitive in property names. Use the canonical capitalization from the ADO type library:ActiveConnection, notactiveconnection. - Do not call
cn->Close()from inside the action body if the connection is reused; close it only in the WinCC shutdown action to avoid tearing down the connection while a peer action is still executing. - When the SQL Server is configured for Force Encryption, add
;Encrypt=yes;TrustServerCertificate=no;to the connection string and install the SQL Server CA certificate in the WinCC station's Trusted Root Certification Authorities store. - For WinCC Professional V18 on TIA Portal, prefer the built-in Database connectivity workflow over manual C scripts for archive queries; reserve the C script path for custom stored procedure calls that the workflow cannot express.
- If the procedure is defined with
WITH EXECUTE AS CALLER, the calling login must have permission on every underlying table.WITH EXECUTE AS OWNERsimplifies this but requiresTRUSTWORTHY ONon the database.
What causes the "property ActiveConnection not available" error in a WinCC C script?
The error is raised when the ADODB.Command object's dispatch interface cannot resolve the ActiveConnection property. The three most common causes are: COM not initialized on the script thread (missing CoInitializeEx), the ADODB.Connection being closed because Open() failed silently, and a 32-bit/64-bit OLE DB provider mismatch between the script editor and runtime. Initialize COM, check the Open() return code, and verify the provider matches the WinCC build.
Should I use MSOLEDBSQL or SQLOLEDB in the WinCC connection string?
Use MSOLEDBSQL for SQL Server 2012 SP4 and later. The legacy SQLOLEDB provider is deprecated and removed from SQL Server 2017+ distributions; continuing to use it on a modern SQL Server produces the same "property not available" symptom when the provider fails to load. SQLNCLI11 remains acceptable but MSOLEDBSQL is the recommended replacement.
Can I call stored procedures with output parameters from a WinCC C script?
Yes. Append a parameter with direction adParamOutput (value 2) or adParamInputOutput (value 3) before calling Execute(), then read the parameter's Value property after the call returns. Use adParamReturnValue (value 4) to capture the stored procedure's return code. Parameters.Refresh() must be called once after CommandText is set so the collection matches the procedure's signature.
Why does the script work in the editor but fail in WinCC Runtime?
The script editor and the runtime can be different bitness (32-bit editor, 64-bit runtime, or vice versa). Each bitness must have a matching MSOLEDBSQL provider installed. A script that compiles and tests successfully in the editor will fail with COM error 0x80004002 if the runtime cannot load the provider. Install both x86 and x64 MSOLEDBSQL versions on the WinCC station when running a mixed-bitness configuration.
Is VBScript a safer choice than C for calling stored procedures in WinCC?
For most teams, yes. The VBScript host handles COM apartment initialization and type-library binding automatically, which removes the two main sources of the "property ActiveConnection not available" error. Use C scripts only when you need to integrate with native C libraries, when the script must run inside a custom DLL action, or when you need precise control over COM lifetime and threading.