title: In multithreading, C# calls C++DLL function error
body: <p>My C# program needs to call C++ functions located in an external DLL.</p>
  <p>I found that it works fine under single thread, but error under multithread.</p>
  <p>C++ code:</p>
  <pre class="lang-cpp prettyprint-override"><code>
  enum ProgramExitType:int {
      ET_ERROR,
      ET_SUCCEED,
      ET_TLE,
      ET_MLE
  };
  enum ProgramErrorType :int {
      PE_UNKNOWN,
      PE_INPUT,
      PE_OUTPUT,
      PE_ERRPUT,
      PE_CREATEPROCESS,
      PE_WAIT,
  
  };
  struct ProgramExitInfo {
      ProgramExitType type;
      ProgramErrorType err_type;
      long long memory_usage;
      int time;
      unsigned int exit_code;
  };
  
  #define ___RR_COMBINE_(x,y) x##y
  #define __RR_COMBINE(x,y) ___RR_COMBINE_(x,y)
  #define UNIQUESYM __RR_COMBINE(__RRLibrary__unique_symbol_,__COUNTER__)
  #define AUTOCLOSE(h) AutoClose UNIQUESYM(h)
  #define AUTOCLOSEREF(h) AutoCloseRef UNIQUESYM(h)
  class AutoClose {
      HANDLE h;
  public:
      AutoClose(HANDLE h) :h(h) {}
      ~AutoClose() { CloseHandle(h);/* LOGW(L&quot;AutoClose\n&quot;); */ }
  };
  class AutoCloseRef {
      HANDLE* h;
  public:
      AutoCloseRef(HANDLE* h) :h(h) {}
      ~AutoCloseRef() { CloseHandle(*h); /* LOGW(L&quot;AutoCloseRef\n&quot;);*/ }
  };
  ProgramExitInfo RunProgram(PCWSTR path, PCWSTR param, PCWSTR input, PCWSTR output, PCWSTR errput, int time_limit, long long memory_limit) {
      //MessageBox(0, L&quot;RunProgram Start&quot;, L&quot;&quot;, MB_ICONINFORMATION);
      ProgramExitInfo ret;
      ZeroMemory(&amp;ret, sizeof(ProgramExitInfo));
      HANDLE hin = INVALID_HANDLE_VALUE, hout = INVALID_HANDLE_VALUE, herr = INVALID_HANDLE_VALUE;
      AUTOCLOSEREF(&amp;hin); AUTOCLOSEREF(&amp;hout); AUTOCLOSEREF(&amp;herr);
      SECURITY_ATTRIBUTES sa;
      sa.nLength = sizeof(sa);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;
  
      if (input != NULL &amp;&amp; *input != 0) {
          //MessageBox(0, input, L&quot;Load Input&quot;, MB_ICONINFORMATION);
          hin = CreateFile(input, GENERIC_READ, FILE_SHARE_READ, &amp;sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
          if (hin == 0 || hin == INVALID_HANDLE_VALUE) {
              ret.type = ET_ERROR;
              ret.err_type = PE_INPUT;
              return ret;
          }
      }
      if (output != NULL &amp;&amp; *output != 0) {
          //MessageBox(0, input, L&quot;Load Output&quot;, MB_ICONINFORMATION);
          hout = CreateFile(output, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &amp;sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
          if (hout == 0 || hout == INVALID_HANDLE_VALUE) {
              ret.type = ET_ERROR;
              ret.err_type = PE_OUTPUT;
              return ret;
          }
      }
      if (errput != NULL &amp;&amp; *errput != 0) {
          //MessageBox(0, input, L&quot;Load Errput&quot;, MB_ICONINFORMATION);
          herr = CreateFile(errput, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &amp;sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
          if (herr == 0 || herr == INVALID_HANDLE_VALUE) {
              ret.type = ET_ERROR;
              ret.err_type = PE_ERRPUT;
              return ret;
          }
      }
  
      STARTUPINFO si = { sizeof(si) };
      si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
      si.wShowWindow = SW_HIDE;
      si.hStdOutput = hout;
      si.hStdError = herr;
      si.hStdInput = hin;
      PROCESS_INFORMATION pi = { 0 };
      wchar_t* param_buff = 0;
      if (param != NULL) {
          param_buff = new wchar_t[lstrlenW(param) + 1];
          lstrcpyW(param_buff, param);
      }
      BOOL b = CreateProcess(path, NULL,
          NULL,
          NULL,
          TRUE,
          NULL,
          NULL,
          NULL,
          &amp;si, &amp;pi);
      if (param_buff != 0)
          delete[] param_buff;
      AUTOCLOSE(pi.hProcess); AUTOCLOSE(pi.hThread);
      if (b == FALSE) {
          ret.type = ET_ERROR;
          ret.err_type = PE_CREATEPROCESS;
          return ret;
      }
      int ti = GetTickCount();
      DWORD dw = WaitForSingleObject(pi.hProcess, time_limit);
      ret.time = GetTickCount() - ti;
      if (dw != WAIT_OBJECT_0)
          TerminateProcess(pi.hProcess, -1);
      GetExitCodeProcess(pi.hProcess, (LPDWORD)&amp;ret.exit_code);
  
      switch (dw) {
      case WAIT_OBJECT_0: {
          break;
      }
      case WAIT_TIMEOUT: {
          ret.type = ET_TLE;
          break;
      }
      default: {
          ret.type = ET_ERROR;
          ret.err_type = PE_WAIT;
          return ret;
      }
      }
      PROCESS_MEMORY_COUNTERS pmc = { 0 };
      GetProcessMemoryInfo(pi.hProcess, &amp;pmc, sizeof(pmc));
      ret.memory_usage = (long long)pmc.PeakWorkingSetSize + pmc.PeakPagefileUsage;
      if (ret.memory_usage &gt; memory_limit) {
          ret.type = ET_MLE;
          return ret;
      }
      ret.type = ET_SUCCEED;
      return ret;
  }
  
  </code></pre>
  <p>C# code:</p>
  <pre class="lang-cs prettyprint-override"><code>[DllImport(&quot;ProgramRunningHelper.dll&quot;, CallingConvention = CallingConvention.Cdecl)]
  public static extern ProgramExitInfo RunProgram([MarshalAs(UnmanagedType.LPWStr)]string path, [MarshalAs(UnmanagedType.LPWStr)]string param, [MarshalAs(UnmanagedType.LPWStr)]string input, [MarshalAs(UnmanagedType.LPWStr)]string output, [MarshalAs(UnmanagedType.LPWStr)]string errput, int time_limit, long memory_limit);
  
  </code></pre>
  <p>I use <code>RunProgram</code> runs different .exe file with different in/output redirections in different thread.</p>
  <p>But the function returns <code>PE_INPUT</code>or<code>PE_OUTPUT</code> which means it cannot create an in/output file.</p>
  <p>I called <code>FindLastError()</code> and get <code>32</code> &quot;Another program is using this file and the process cannot access it.&quot;</p>
  <p>But if there is only one thread, no any errors.</p>
  <p>So I think this may be because the parameters passed by different threads are confused( For example, there are two threads passing parameters 'a' and 'b' respectively, but CLR considers that both of them passed 'a'. ). Is it possible?</p>
  <p>How can I solve it?</p>
  <p>Any help would be much appreciated !</p>