When an OPC client faults about every 30 minutes and Event Viewer names ntdll.dll or oleaut32.dll, those module names are where the exception surfaced, not the culprit. If the OPC server keeps its values cached, switch the client to synchronous reads, then require a clean window of four times the usual interval, about 2 hours, before calling the crash fixed.
An OPC client that faults about every 30 minutes points at the OPC data path first, and the fix that holds on servers that cache their values is to read synchronously. Event Viewer will name ntdll.dll or oleaut32.dll as the faulting module. That name is the address where the exception surfaced, not the verdict on the file, so never replace either file. Turn off asynchronous communication in the OPC client, change nothing else on the station, and judge the change by a clean window of four of the usual intervals: about 2 hours on a 30-minute fault. This page explains what the log entries mean, which symptoms point where, and how to prove the fix on your own timestamps.
What the faulting application and faulting module lines mean
Windows writes every application crash to Event Viewer, and two lines matter here. Faulting application names the program that stopped; on this fault it is the OPC client's own executable. Faulting module names the system file that was executing when the exception fired, most often ntdll.dll or oleaut32.dll on this fault.
ntdll.dll is a core Windows file that nearly every program runs through. oleaut32.dll carries OLE automation, the data-sharing layer that COM-based software such as an OPC client uses to move values between programs. One exception can pass through both files before the process stops, which is why the entry lists the pair.
The entry records where the exception surfaced. It does not prove that the named file is damaged: a fault in the client's own code or in the OPC exchange can surface through a Windows file. Open the event entry in Event Viewer, read the faulting application and faulting module lines together, and copy the full entry, including the exception code, before you change anything.
Symptoms and what each points to
- A crash on a near-fixed period, about every 30 minutes, with the client executable named as the faulting application and ntdll.dll or oleaut32.dll as the module. That points at the OPC data path, and the client's communication mode is the first setting to test.
- A crash that lands right after a burst of values or after one device reports in. That points at asynchronous update handling and callback volume. The same overload logic breaks the receiving end in the crash caused by HMI UDP polling traffic.
- A faulting module that belongs to the OPC server vendor instead of Windows. That points at the vendor's own component; send the full event text with the exception code to the vendor.
- Entries in the same log from software the controls system never needed, such as a database guardian service or a media sync service. That points at the station's software inventory. List what is installed and what each service belongs to, and test any removal separately.
- A crash that stops for a day or two after any change, then returns. That points at variables that were never isolated. Change one setting per test and keep the timestamps.
Why synchronous reads stop this crash
Servers of the kind behind this fault keep every point's value cached in memory at all times. That is exactly why a synchronous read works: the answer is already in the cache when the client asks, so the server returns it on the spot. Asynchronous updates are the tool for a different design, one where the server must poll the hardware before the physical value is known.
On a cached server, every asynchronous subscription is extra work: the client holds callbacks, receives update bursts and marshals bulk data through oleaut32.dll for values it could have read on demand. Turn asynchronous communication off and that whole path disappears. That is why the crash interval changes when the mode changes.
General OPC guidance still prefers asynchronous reads and writes because they are usually more efficient, so keep asynchronous as the default and use the switch when both statements hold: the server caches values, and the crash evidence points at the update path. If the choice between a small hand-written client and a packaged OPC server is still open, settle it first with write a Modbus client or use an OPC server for a small HMI.
Ask operations one question before the test: can the board tolerate a value that is one read cycle old? On a cached server the cache is as fresh as the server's own device polling, so for a status board the answer is almost always yes.
Checks before you change the mode
- Record the baseline. Note the current communication mode in the client's connection settings, and copy every crash entry from Event Viewer with its timestamp and exception code. This is the same timestamp-first discipline used for an HMI protocol error that pops up every 30 seconds.
- Get the freshness answer in writing. Operations confirms what breaks if a displayed value is one read cycle old. This is the safety check for the test.
- Inventory the station. Match the installed-program list and the services list against what the controls system needs. Change nothing yet.
- Leave the system files alone. Never download a replacement ntdll.dll or oleaut32.dll from a file site. If genuine file damage ever shows up, repair with Windows' built-in repair tool from an administrator command prompt, then retest.
The fix: switch the client to synchronous reads
The mode lives in the OPC client's connection or channel settings, among the communication and update options; on the case behind this fault it is described as turning off asynchronous comms in the OPC client. Set the mode to synchronous or clear the asynchronous option, restart the client, and touch nothing else on the station.
Confirm two things before the clock starts: values still update when the client reads them, and any command the client sends still agrees with the field device. Write down the previous setting so a rollback is one change. Then judge the result by interval, and the next section does that on real timestamps.
Worked example: a client that faults about every 30 minutes
Inputs. Crash timestamps from Event Viewer before any change: 10:12, 10:41 and 11:13, typical values for this fault, whose observed return period is about 30 minutes. Restart with synchronous reads at 11:30. Test rule: four clean intervals.
The rule in words. Measure the interval between consecutive crashes and confirm it matches the reported period. After the switch, require a clean window of four of those intervals before calling the change a fix; four gives the fault several chances to return on its own schedule.
The arithmetic.
- From 10:12 to 10:41 is 29 minutes.
- From 10:41 to 11:13 is 32 minutes.
- Mean interval: (29 + 32) ÷ 2 = 30.5 minutes, which matches the reported about-30-minute fault.
- Test window: 4 × 30 minutes = 120 minutes, so the switch at 11:30 sets the decision point at 13:30.
The result and the decision.
- No crash by 13:30: four clean intervals have passed. The change is holding; let it run out the shift and log the old and new settings.
- A crash by about 12:00, one interval after the switch: the communication mode is ruled out as the trigger. Move to the next suspects in order, update volume first, the station's software inventory second.
- One crash between 12:00 and 13:30, say at 13:05: the interval stretched from 30.5 minutes to 95 minutes. Keep the synchronous setting and extend the window to 10 intervals, 5 hours, before deciding.
The thresholds: four clean intervals hold the fix; a crash inside the first interval rules the mode out; anything between extends the test.
The decision for each case
Recommendation: If your OPC server keeps every point's value cached, switch the client from asynchronous updates to synchronous reads, change nothing else on the station, and call the fix good only after four clean intervals, 2 hours on a 30-minute fault; then soak it through a full production week with the old setting recorded for rollback. If the server must poll hardware before a value is known, keep asynchronous communication and work the other causes in order: update volume, then the station's software inventory. Whatever the mode, never replace ntdll.dll or oleaut32.dll from a file-download site.
Questions
Why do two faulting modules show up for one crash?
An exception can pass through several system files before the process stops, so the entry lists the modules on that path. ntdll.dll sits underneath nearly every Windows program and oleaut32.dll carries OLE automation data between applications, which is why both turn up in crashes that have nothing in common. The pair is a signature of where the process stopped, not of one damaged file.
Does ntdll.dll in the log mean the station has a virus?
Judge the risk by the station's exposure, not by the module name. ntdll.dll runs under nearly every Windows program, legitimate and malicious alike, so the name matches both. If the station sits offline with a short, known software list, spend the time on the OPC data path. If it reaches the internet or runs untracked software, clean and update it first, then retest the crash before drawing any conclusion.
How long should the station run clean before I close the ticket?
Use the four-interval rule as the minimum: on a 30-minute fault that is a 2-hour clean window. For a board that operations relies on, let the client soak through a full production week after that, with the previous setting recorded so a rollback is one change. If the crash returns later at a stretched interval, reopen the ticket and compare the new timestamps against the old ones.
Planning information, not legal or engineering advice. Rules differ by place: check codes and permits with your local authority and your licensed trades.