Repository navigation
Expand file tree
/
Copy pathWinMsgBox.cpp
More file actions
170 lines (147 loc) · 4.94 KB
/
Copy pathWinMsgBox.cpp
File metadata and controls
170 lines (147 loc) · 4.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*******************************************************************************
* WinMsgBox.cpp -- DLL component code to demonstrate displaying a Windows
* message box and getting a user's response.
*
* See https://github.com/robdunn4/QSpice/ for complete documentation & code.
******************************************************************************/
/*
* Notes:
*
* (1) This code can be compiled with the DMC compiler included with QSpice.
*
* (2) The below GUI_HWND declaration is supported by the 2025.06.26 and
* later releases of QSpice. It may or may not be generated by the
* QSpice C++ code template generator. If not, you'll can manually
* add it to your code.
*
* (3) This example simply displays a message box to the user when the
* Vtrig input port goes high. The user can choose to abort the
* simulation, continue until the next trigger event, or ignore
* future trigger events. You can, of course, implement it in any
* fashion that is useful for your particular application.
*
* Possible use cases:
* * Log file exists. Overwrite, append, or cancel?
* * Missing or corrupt configuration file. Continue using defaults?
* * A large amount of data has been logged. Continue logging?
* * Input port X value is out of expected range. Continue?
*/
#include <Windows.h>
#include <stdio.h>
extern "C" __declspec(dllexport) int (*Display)(const char *format, ...) = 0;
extern "C" __declspec(dllexport) void *GUI_HWND = 0; // <-- manually added
union uData {
bool b;
char c;
unsigned char uc;
short s;
unsigned short us;
int i;
unsigned int ui;
float f;
double d;
long long int i64;
unsigned long long int ui64;
char *str;
unsigned char *bytes;
};
// int DllMain() must exist and return 1 for a process to load the .DLL
// See https://docs.microsoft.com/en-us/windows/win32/dlls/dllmain for more
// information.
int __stdcall DllMain(void *module, unsigned int reason, void *reserved) {
return 1;
}
/*
* Per-instance data structure
*/
struct InstData {
bool bTrigState; // last Vtrig input state
bool bIgnore; // ignore subsequent trigger events
bool bTerminate; // terminate ASAP
};
// forward declarations
int doMsg(double t);
/*
* QSpice evaluation function
*/
extern "C" __declspec(dllexport) void winmsgbox(
InstData **ppInst, double t, uData *data) {
double Vin = data[0].d; // input
bool Vtrig = data[1].b; // input
double &Vout = data[2].d; // output
/* initialization section */
InstData *pInst = *ppInst;
if (!pInst) {
// allocate and clearper-instance data
pInst = *ppInst = (InstData *)calloc(1, sizeof(InstData));
// debug testing message...
Display("GUI_HWND=0x%08x\n", static_cast<HWND>(GUI_HWND));
// GUI_HWND is null if run from the command line; we'll suppress
// messages but it is valid to allow them -- comment out to test
// that behavior
if (GUI_HWND == NULL) pInst->bIgnore = true;
}
/* implementation section */
Vout = Vin;
// if trigger unchanged, quick out
if (pInst->bTrigState == Vtrig) return;
// trigger changed, save the state
pInst->bTrigState = Vtrig;
// if ignoring triggers, quick out
if (pInst->bIgnore) return;
// if not rising edge, quick out
if (!Vtrig) return;
// for debugging...
Display("Trigger event detected @t=%lf\n", t);
// display msgbox, get user response
int res = doMsg(t);
switch (res) {
case IDABORT:
Display("User selected Abort...\n");
pInst->bTerminate = true;
break;
case IDRETRY:
Display("User selected Retry...\n");
break;
case IDIGNORE:
pInst->bIgnore = true;
Display("User selected Ignore...\n");
break;
}
}
/*
* MaxExtStepSize() for terminating gracefully
*/
extern "C" __declspec(dllexport) double MaxExtStepSize(
InstData *pInst, double t) {
static double maxStep = 1e308;
static double termSim = -1e308;
if (pInst->bTerminate) {
Display("Terminating simulation \"gracefully\" @ t=%lf...\n", t);
return termSim;
}
return maxStep;
}
/*
* release allocated per-instance data
*/
extern "C" __declspec(dllexport) void Destroy(InstData *pInst) { free(pInst); }
/*
* display message box & get/return user response
*
* note: search "WinAPI MessageBoxA()" for parameter details
*/
int doMsg(double t) {
// we should use snprintf() here but DMC compiler implements C++98 and
// snprintf() isn't a thing until C++11...
char msg[512];
sprintf(msg,
"Trigger event detected @t=%lf\n\n"
"Abort to terminate simulation,\nRetry to continue until next "
"event,\nor Ignore to ignore subsequent events",
t);
// show the msgbox, return result
int res = MessageBoxA(static_cast<HWND>(GUI_HWND), msg, "WinMsgBox",
MB_ABORTRETRYIGNORE | MB_ICONERROR | MB_APPLMODAL);
return res;
}