Overview
Siemens WinCC (both the legacy V7.x SCADA and the TIA Portal WinCC Professional / Comfort / Advanced HMI lines) provides a built-in tag data export that writes a .csv file. The user requirement that recurs in the field is to have the columns already separated when the CSV is opened in Excel, without using the standard , or ; delimiter option exposed by the WinCC export dialog. This is a misframed problem: a CSV file is, by definition, a comma-separated value file, so the only thing that can be changed is the character that acts as the separator. The two real engineering options are:
- Substitute the delimiter character (tab, semicolon, pipe, etc.) so the file is still a CSV semantically but is not the default
,file. - Skip the CSV layer entirely and write a native Excel workbook (XLS / XLSX) from a WinCC C script using OLE Automation. This is the only method that produces a file with separated columns in Excel without any delimiter at all.
sep= line directive, and the Windows regional list separator are all part of the same problem space. See Import or export text (.txt or .csv) files - Microsoft Support for the underlying Excel behaviour.Why CSV Cannot Have "No Delimiter"
A CSV file stores tabular data as plain text. Each row is a line ending in \r\n (or \n), and each column is terminated by a single character - the field separator. The W3C / RFC 4180 specification uses ,; Excel on a German, French, Spanish, Italian, or Portuguese Windows installation uses ; because the regional list separator is set to semicolon. If no character is placed between two values, Excel reads them as a single column.
Three practical consequences for a WinCC export script:
- There is no "no delimiter" mode. There is only "delimiter = X" where X is one byte.
- The character you choose must never appear inside a tag value (no commas in tag comments, no semicolons in tag names, etc.). The tab character
\t(0x09) is the safest pick because it is almost never present in HMI tag strings. - If you need true column separation in Excel, write
.xlsxusing OLE Automation. CSV cannot give you "no delimiter".
Prerequisites
- WinCC V7.4 SP1 or later, or TIA Portal V15.1 or later with WinCC Professional / Comfort / Advanced runtime.
- WinCC project with the Global Script / Scripts C editor enabled (default in V7.x, requires "Scripting" support in TIA Portal HMI configuration).
- For the OLE Automation method: Microsoft Excel installed on the HMI runtime PC and the Microsoft Excel Object Library typelib accessible (it is installed with Office). On a WinCC RT PC, the
EXCEL.EXEmust be present; the standard SCADA license does not include Office. - For the C script method, the standard C runtime file I/O functions are available:
fopen,fprintf,fclose,sysFile(WinCC wrapper), andprintf.
Method 1 - Configure the Delimiter in the WinCC Export Dialog
Before going to script, the most common cause of "the delimiter does not work" is that the operator opened the CSV on a workstation with a different Windows regional setting. WinCC uses the Windows list separator from the regional settings of the runtime PC that wrote the file, while Excel uses the list separator of the workstation that opens the file.
- On the engineering station, open Control Panel → Region → Additional settings.
- Confirm List separator is set to
;(common in Europe) or,(common in US/UK). - Restart the WinCC runtime so it picks up the new setting.
This is not a "no delimiter" solution, but it is the answer to 80 % of the field tickets where "the columns are not separated".
Method 2 - C Script with a Custom Delimiter (Tab, Pipe, or Comma)
The simplest scripted export. Use a C action triggered by a button or a scheduled task. The script writes tag values to a text file, inserting \t between fields. When the file is opened in Excel, the tab is recognised and the data lands in separate columns.
// WinCC V7.x C action - export tags to a tab-separated file
#include "apdefap.h"
void ExportTags_Tab()
{
FILE *fp;
char szFileName[256];
char szTime[32];
DWORD dwTime;
float fValue1, fValue2, fValue3;
char szString1[64];
// Resolve runtime tag handles once (avoid GetTag calls inside the loop)
fValue1 = GetTagFloat("Process_Temperature");
fValue2 = GetTagFloat("Process_Pressure");
fValue3 = GetTagFloat("Process_Flow");
strcpy(szString1, (char*)GetTagChar("Process_State"));
dwTime = GetTickCount();
sprintf(szTime, "%u", dwTime);
strcpy(szFileName, "C:\\Export\\TagLog_");
strcat(szFileName, szTime);
strcat(szFileName, ".csv"); // file extension is cosmetic; it is TSV in fact
fp = fopen(szFileName, "a+");
if (fp == NULL) {
printf("Export failed: cannot open %s\n", szFileName);
return;
}
// Header line, tab-separated, CRLF line ending
fprintf(fp, "Time\tTemperature\tPressure\tFlow\tState\r\n");
// Data line, tab-separated
fprintf(fp, "%s\t%.2f\t%.2f\t%.2f\t%s\r\n",
szTime, fValue1, fValue2, fValue3, szString1);
fclose(fp);
printf("Export OK: %s\n", szFileName);
}
Notes for production use:
- Replace the manual filename with a real timestamp; WinCC supplies
SysGetTimeString/SysTimestructures inapdefap.h. - On non-English Windows installations, change the literal
","/"."in theprintfformat string only if you genuinely need to bypass regional settings; otherwise leave it so the file is locale-correct. - Use
\tas the field separator. This is the byte0x09and is invisible in Notepad, but Excel treats it as a true column break. - When the operator double-clicks the file, Excel may pop up the Text Import Wizard. The user should choose Delimited → Tab. To skip this, name the file with the
.txtextension and pre-pend thesep=tabdirective on the first line (Excel recognises the BOM-prefixed UTF-8 form). This works in Excel 2016, 2019, 2021, and Microsoft 365.
Method 3 - C Script with OLE Automation (Real Excel File, No Delimiter)
If the requirement is literally no delimiter and the file must open as a normal .xlsx with the data already in cells, the only path is to drive Excel from the C script. WinCC C supports COM through the comutil wrappers and the ole32 calls. The example below uses a VBScript-style C wrapper to keep the code readable. The Excel Worksheet.Cells(row, col) property is what produces the column break - no separator character is ever written.
// WinCC V7.x C action - export tags directly to a real .xlsx workbook
#include "apdefap.h"
#import "C:\\Program Files (x86)\\Common Files\\microsoft shared\\OFFICE16\\MSO.DLL" \
rename("RGB", "MSORGB")
#import "C:\\Program Files\\Microsoft Office\\root\\Office16\\EXCEL.EXE" \
rename("RGB", "EXRGB")
void ExportTags_Excel()
{
// Initialise COM for this thread
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
Excel::_ApplicationPtr pApp;
Excel::_WorkbookPtr pBook;
Excel::_WorksheetPtr pSheet;
Excel::RangePtr pRange;
HRESULT hr;
hr = pApp.CreateInstance("Excel.Application");
if (FAILED(hr)) {
printf("Excel not available, hr=0x%08X\n", hr);
CoUninitialize();
return;
}
pApp->Visible = VARIANT_FALSE;
pApp->DisplayAlerts = VARIANT_FALSE;
pBook = pApp->Workbooks->Add();
pSheet = pBook->ActiveSheet;
pSheet->Name = "TagExport";
// Header row - 5 cells, 5 columns, NO delimiter involved
pSheet->Cells->Item[1,1]->PutValue("Time");
pSheet->Cells->Item[1,2]->PutValue("Temperature");
pSheet->Item[1,3]->PutValue("Pressure");
pSheet->Item[1,4]->PutValue("Flow");
pSheet->Item[1,5]->PutValue("State");
// Data row from live tags
pSheet->Cells->Item[2,1]->PutValue((const char*)GetTagChar("Export_Timestamp"));
pSheet->Cells->Item[2,2]->PutValue(GetTagFloat("Process_Temperature"));
pSheet->Cells->Item[2,3]->PutValue(GetTagFloat("Process_Pressure"));
pSheet->Cells->Item[2,4]->PutValue(GetTagFloat("Process_Flow"));
pSheet->Cells->Item[2,5]->PutValue((const char*)GetTagChar("Process_State"));
// Save as xlsx with COM Variant filename
_variant_t vtFileName = "C:\\Export\\TagExport.xlsx";
pBook->SaveAs(vtFileName,
_variant_t((long)51), // xlOpenXMLWorkbook (.xlsx)
vtMissing, vtMissing, vtMissing,
vtMissing, vtMissing,
Excel::xlNoChange,
vtMissing, vtMissing, vtMissing, vtMissing);
pBook->Close(VARIANT_FALSE);
pApp->Quit();
pRange = pSheet = pBook = pApp = NULL;
CoUninitialize();
printf("Excel export OK.\n");
}
Operational notes:
- The path to
MSO.DLLandEXCEL.EXEmust match the Office version installed on the runtime PC. Common paths: Office 2016/2019/2021 =Program Files\Microsoft Office\root\Office16, Office 2013 =Program Files (x86)\Microsoft Office\Office15, Microsoft 365 =Program Files\Microsoft Office\root\Office16. -
xlOpenXMLWorkbook = 51writes.xlsx. Use50for.xls. - Excel must stay installed on the RT PC. Office runtime activation is not required if no user opens the UI; headless automation uses the default license key.
- For TIA Portal WinCC Professional the same code works; the C action is configured under HMI tags → Connections → Scripts with the typelibs listed under Scripting settings → COM references.
Method 4 - C Script to Tab-Separated File + Excel "sep=" Directive
This is a hybrid. Write a tab-separated file but tell Excel the separator is tab on the first line, so the file opens in columns with no manual wizard. The trick: the first line of the file is sep=tab followed by \r\n. Excel 2016+ honours it.
// C action - tab-separated file with sep= directive
void ExportTags_SepTab()
{
FILE *fp;
fp = fopen("C:\\Export\\Log.csv", "w");
if (!fp) return;
fprintf(fp, "sep=tab\r\n");
fprintf(fp, "Time\tTemperature\tPressure\tFlow\tState\r\n");
fprintf(fp, "%s\t%.2f\t%.2f\t%.2f\t%s\r\n",
(const char*)GetTagChar("Export_Timestamp"),
GetTagFloat("Process_Temperature"),
GetTagFloat("Process_Pressure"),
GetTagFloat("Process_Flow"),
(const char*)GetTagChar("Process_State"));
fclose(fp);
}
Be aware of the Microsoft guidance in Import or export text (.txt or .csv) files - Microsoft Support: the sep= directive overrides only the current file's import behaviour. If the user opens the file with Data → From Text/CSV in Power Query, the directive is ignored and the comma default is used. Test on the target Office version before deploying.
Tag Value Escaping and Edge Cases
Any of the tab, comma, semicolon, or OLE methods fail the same way when tag values contain the separator character. Recommended rules:
| Tag type | Recommended separator | Why |
|---|---|---|
| Numeric floats, integers | Tab \t
|
Numeric values do not contain 0x09. |
| Boolean text ("ON"/"OFF") | Tab \t
|
Safe. |
| Operator comments, free text | Tab \t + quote wrap with \"
|
Excel handles quoted fields with embedded delimiters. |
| Multi-line text (alarm messages) | Replace \r\n inside the value with [CR][LF] literal |
Otherwise one row splits into two in Excel. |
| Real Excel export | OLE Automation, no separator needed | Cells are placed in the worksheet directly; embedded \r\n in PutValue only inserts a hard line break inside the cell. |
Verification Steps
- Trigger the export action and open the resulting file in Notepad. Confirm each line contains the expected separator character (0x09 for tab, 0x3B for semicolon, 0x2C for comma).
- Open the file in Excel with Data → From Text/CSV. Verify each tag occupies its own column, with the right header in row 1.
- If columns are merged, open Control Panel → Region → Additional settings → List separator on the workstation and change it. Re-open the file. The setting affects every CSV opened in Excel, not only this one.
- For the OLE method, verify
EXCEL.EXEis closed after the script runs. A lingeringEXCEL.EXEin Task Manager indicates a COM object was not released; review theNULLassignments andCoUninitializecall. - For the tab method with
sep=tab, verify on the lowest Office version on site. Office 2010 and earlier ignore the directive. - Add a 1-second
Sleepafter the export, then compare the file mtime to confirm the file was rewritten on every trigger and is not locked by a previous open Excel instance.
Troubleshooting Matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| All data lands in column A | Excel list separator is , but the file uses ;, or vice versa |
Match the file's separator to the regional setting, or rename file to .txt and use the wizard |
| Text Import Wizard appears | File extension is .csv and Excel does not auto-detect |
Add the sep=tab first line, or use OLE Automation to write .xlsx
|
| Some rows split into two | Tag value contains a literal \r\n
|
Replace newlines inside the value before writing |
| Header is shifted by one column on some workstations | BOM (byte order mark) present, sep= directive misread |
Write the file as plain ANSI or UTF-8 without BOM |
| "Excel not available, hr=0x80040154" | Office not installed or wrong path in #import
|
Install Excel or correct the path; check the DCOM permissions for the WinCC runtime user |
| Export button does nothing | WinCC C action is not compiled | Open the script in the WinCC C editor, right-click → Compile, and check the diagnostics window |
| File is locked after a Power Loss recovery | Previous EXCEL.EXE did not exit |
Kill orphan Excel processes in Task Manager, or move to headless automation via Open XML SDK (no Excel process) |
Performance and Logging Considerations
WinCC's own tag logging writes its own .csv files through the Tag Logging / Logging editor, and the default export uses the Windows list separator. For long historical dumps (millions of rows), prefer the built-in export and process the file in Power Query or Python (pandas) - both handle the regional separator natively and let you specify sep="\t" or sep=";" at load time. The C script path above is for live snapshots, not for full history dumps.
For headless export without Office installed on the runtime, the modern path is the Open XML SDK producing a true .xlsx from any language. This avoids both the COM dependency and the "no delimiter" requirement because the file is a real OOXML workbook.
FAQ
Can a CSV file really have no delimiter?
No. CSV is defined by the separator character that splits fields on a row. The only knob is which character is the separator. The tab character (0x09) is the safest non-comma choice because it almost never appears inside HMI tag values.
Why do my columns merge when I open the CSV in Excel?
Excel uses the Windows regional list separator of the workstation that opens the file, not the one on the runtime that wrote the file. Match the two, or change the file extension to .txt and use the Text Import Wizard, or use the sep=tab first-line directive.
How do I get a real Excel file with the columns already separated?
Write an .xlsx directly from a WinCC C action using Excel OLE Automation, calling Worksheet.Cells[row, column].PutValue for each value. The file is a real Excel workbook, no separator character is involved, and the columns are separated by virtue of the cell addresses.
Which Office version is needed on the WinCC runtime PC?
Any version with the Excel COM typelib (Office 2010 or later) is sufficient for OLE Automation. The EXCEL.EXE and MSO.DLL paths in the #import directives must match the installed version; the path differs between Office 2013, 2016, 2019, 2021, and Microsoft 365.
Does the C script approach work in TIA Portal WinCC Professional?
Yes. The same C runtime functions (fopen, fprintf, GetTagFloat, GetTagChar) are available in TIA Portal HMI scripts. Configure the action on a button or a scheduled task, enable the typelib references under Scripts → COM references, and recompile before downloading to the HMI.