CAPL (Communication Access Programming Language) is the event-driven scripting language
for Vector CANoe/CANalyzer. It follows C89/C90 syntax constraints — no C99 or
C++ features. This skill provides corrected, production-ready reference material for
automotive diagnostic security testing with CAPL + DLL two-layer architecture.
// comments in strict C89 (CAPL compiler accepts them, but avoid for portability)snprintf — use sprintf (ensure buffer is large enough)strncpy_s — use strncpy, manually null-terminate_atoi64 — use atol() or parse hex manually{} is NOT supported — assign element by elementTestWaitForTimeout, TestStep, etc./*@!Encoding:936*/
includes
{
#include "Common.can"
}
variables
{
msTimer tCycle;
message 0x123 msg_Test;
long gCounter;
byte gData[8];
}
on start
{
gCounter = 0;
setTimer(tCycle, 100);
}
on timer tCycle
{
gCounter++;
msg_Test.dlc = 8;
msg_Test.byte(0) = gCounter;
output(msg_Test);
setTimer(tCycle, 100);
}
on message 0x456
{
write("Rx 0x456 byte0=0x%02X", this.byte(0));
}
| Event | Trigger | Typical Use |
|---|---|---|
| ------- | --------- | ------------- |
on preStart | Before measurement | Pre-init |
on start | Measurement starts | Init, start timers |
on stopMeasurement | Measurement stops | Cleanup |
on message ID | Specific CAN frame received | Response logic |
on message * | Any CAN frame | Logging (use with caution) |
on timer tName | Timer expires | Periodic tasks, timeouts |
on key 'c' | Key press | Manual trigger |
on sysvar_update | SysVar changes | Panel/automation trigger |
on signal SigName | Signal value changes | Signal-based logic |
variables
{
message 0x100 msg_Tx;
message EngineData msg_Engine; /* DB-backed message */
}
on start
{
msg_Tx.dlc = 8;
msg_Tx.byte(0) = 0x11;
output(msg_Tx);
}
/* Access DB signal */
on message EngineData
{
write("Speed=%f", this.EngineSpeed);
}
/* Write signal and send */
on key 's'
{
msg_Engine.EngineSpeed = 1000;
output(msg_Engine);
}
testcase TC_SecurityAccess()
{
TestCaseTitle("TC_SA_01", "Security Access Level 1");
TestStep("SendSeed", "Send 27 01 RequestSeed");
/* send request... */
if (TestWaitForMessage(0x708, 1000) == 1)
{
TestStepPass("CheckResp", "Response received");
}
else
{
TestStepFail("CheckResp", "Response timeout");
}
}
Correct function names:
| Wrong (lowercase) | Correct (PascalCase) |
|---|---|
| ------------------- | ------------------------ |
testWaitForTimeout | TestWaitForTimeout |
testStep | TestStep |
testStepPass | TestStepPass |
testStepFail | TestStepFail |
testCaseTitle | TestCaseTitle |
All take two parameters (name, description):
TestStep("StepName", "Description of what is being done");
TestStepPass("StepName", "Reason for pass");
TestStepFail("StepName", "Reason for failure");
CRITICAL: CAPL DLL functions are NOT discovered via the Windows DLL export table.
They are registered in a special CAPL_DLL_INFO4 table[] array that CANoe
reads at load time. This is completely different from standard __declspec(dllexport).
Path varies by version, search for CAPLdll under:
C:\Users\Public\Documents\Vector\CANoe <version>\Sample Configurations\Programming\CAPLdll
Open the .sln in Visual Studio. The sample project already has:
CAPL_DLL_INFO4 table[] format for your CANoe versionCAPL_DLL_CDECL, CAPL_FARCALL, etc.)onCaplInit() / onCaplExit() wiringIn capldll.cpp, add your function following the same pattern as existing functions:
long MyAdd(long a, long b)
{
return a + b;
}
Add an entry to the table (format varies by CANoe version — **always copy from the
existing entries in your sample project**):
CAPL_DLL_INFO4 table[] =
{
/* existing entries — do NOT remove */
{
"MyAdd",
(CAPL_FARCALL)MyAdd,
"long",
"long a, long b",
CAPL_DLL_CDECL,
0,
CDLL_EXPORT
},
{ 0, 0 } /* END MARKER — must keep */
};
Field meanings:
"MyAdd" — function name visible to CAPL(CAPL_FARCALL)MyAdd — function pointer"long" — return type string (tells CAPL the return type)"long a, long b" — parameter types string (tells CAPL the argument types)CAPL_DLL_CDECL — calling convention (use the macro from the sample project)0 — reservedCDLL_EXPORT — export flagThe { 0, 0 } entry MUST be the last entry — it is the table terminator.
| Setting | Value | Why |
|---|---|---|
| --------- | ------- | ----- |
| Platform | Win32 or x64 | MUST match CANoe bitness exactly |
| Config | Release (deploy) / Debug (dev) | |
| Runtime Library | /MD (recommended) | Avoid /MT — causes cross-boundary memory issues |
| Character Set | Multi-Byte or Unicode | Match your CAPL string encoding |
Note: The reference document mentions /MT (static CRT) as an option to avoid
needing VC++ redistributable on target machines. This works BUT beware:
Configuration → Programming → CAPL DLL (or Options → CAPL → DLL).dll fileon key 't'
{
long ret;
ret = MyAdd(10, 20);
write("MyAdd(10,20) = %d", ret);
}
| Type String | C/C++ Type | Direction | Notes |
|---|---|---|---|
| ------------ | ------------- | ----------- | ------- |
"long" | long | in/out | Most common |
"double" | double | in/out | |
"char*" | char* | reference | String buffer |
"byte*" | unsigned char* | reference | Binary data |
"VALUE" | value | in | By value (numbers) |
"REFERENCE" | pointer | in/out | For arrays, strings, output buffers |
For arrays/buffers, always pass the length as a separate long parameter:
long ProcessData(unsigned char* data, long len)
{
if (data == 0 || len <= 0) return -1;
/* process data[0] to data[len-1] */
return 0;
}
See references/capl_pitfalls.md for the full list with explanations.
references/capl_pitfalls.md — Detailed pitfall explanations and correctionsreferences/capl_test_templates.md — Reusable test case templates for UDS/securityreferences/capl_dll_guide.md — DLL compilation and CAPL_DLL_INFO4 integration guidereferences/capl_pitfalls.md when user reports a CAPL errorreferences/capl_test_templates.md共 1 个版本