| 148 | |
| 149 | |
| 150 | HANDLE apiCreateThread(LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, LPDWORD lpThreadId, LPCSTR asThreadNameFormat /*= NULL*/, int anFormatArg /*= 0*/) |
| 151 | { |
| 152 | HANDLE hThread = NULL; |
| 153 | ConEmuThreadStartArg* args = new ConEmuThreadStartArg(lpStartAddress, lpParameter, GetCurrentThreadId()); |
| 154 | if (!args) |
| 155 | { |
| 156 | // Not enough memory |
| 157 | return NULL; |
| 158 | } |
| 159 | |
| 160 | // Set user-friendly thread name for VisualStudio debugger |
| 161 | if (asThreadNameFormat && *asThreadNameFormat) |
| 162 | { |
| 163 | if (strchr(asThreadNameFormat, '%') != NULL) |
| 164 | { |
| 165 | INT_PTR cchMax = strlen(asThreadNameFormat) + 64; |
| 166 | char* pszNewName = new char[cchMax]; |
| 167 | if (pszNewName) |
| 168 | { |
| 169 | sprintf_c(pszNewName, cchMax/*#SECURELEN*/, asThreadNameFormat, anFormatArg); |
| 170 | _ASSERTE(strlen(pszNewName) < THREAD_MAX_NAME_LEN); |
| 171 | lstrcpynA(args->sName, pszNewName, countof(args->sName)); |
| 172 | delete[] pszNewName; |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | if (args->sName[0] == 0) |
| 177 | { |
| 178 | _ASSERTE(strlen(asThreadNameFormat) < THREAD_MAX_NAME_LEN); |
| 179 | lstrcpynA(args->sName, asThreadNameFormat, countof(args->sName)); |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | // Start the thread |
| 184 | hThread = ::CreateThread(NULL, 0, apiThreadHelper, args, CREATE_SUSPENDED, lpThreadId); |
| 185 | DWORD nLastError = GetLastError(); |
| 186 | if (hThread) |
| 187 | { |
| 188 | args->hThread = hThread; |
| 189 | ResumeThread(hThread); |
| 190 | } |
| 191 | else |
| 192 | { |
| 193 | delete args; |
| 194 | } |
| 195 | |
| 196 | // Done |
| 197 | SetLastError(nLastError); |
| 198 | return hThread; |
| 199 | } |
| 200 | |
| 201 | BOOL apiTerminateThreadEx(HANDLE hThread, DWORD dwExitCode, LPCSTR asFile, int anLine) |
| 202 | { |
no test coverage detected