title: GetFunctionPointerForDelegate callback only works once
body: <p>I'm having trouble with unmanaged-to-managed callback in C++/CLI.   It works exactly one time and then silently fails</p>
  <p>My managed <code>Device</code> class holds an unmanaged object (<code>GsDevice</code>) from a separate DLL.  It gives the unamanaged object a callback function set up via interop.  <code>GsDevice</code> needs to asynchronously notify Device when things change.</p>
  <p>The callback was silently failing every time.  The debugger was stepping right over it (even in dissasembly.  Then I tried to make <code>GsDevice</code> invoke the callback it as the moment it received it.  THEN it works.  Just the one time.</p>
  <p>I assume  something is being moved or garbage-collected out from under me but I cannot determine what or why.  Can anyone spot what I am doing wrong?</p>
  <p>Below is the <em>unmanaged</em> <code>GsDevice</code> class.  It lives in a separate, unmanaged DLL.  I've left out most of it except for the subscription mechanism that the managed client uses and the notify mechanism by which the this class calls back to the managed one.</p>
  <p>The .H file</p>
  <pre><code>struct GsDeviceMembers;
  class GsDevice : public std::enable_shared_from_this&lt;GsDevice&gt;
  {
      GsDeviceMembers* m_p;   // PIMPL idiom
  
  public:
      typedef void (__stdcall *PROPCHANGECALLBACK)(GsDevice*, const std::string&amp;);
      void GsDeviceDllExport setPropertyChangedCallback(PROPCHANGECALLBACK cb);
  protected:
      void raisePropertyChanged(const std::string&amp; prop);
  }
  </code></pre>
  <p>And the .CPP file</p>
  <pre><code>void GsDevice::setPropertyChangedCallback(PROPCHANGECALLBACK cb)
  {
      std::unique_lock&lt;std::mutex&gt; lk (m_d-&gt;mtxClients);
      cb(this, std::string(&quot;joe&quot;));   // TEST:  Call callback right away to ensure it's good.
      m_p-&gt;cb = cb;                   // Save off the one client's callback
  }
  
  void GsDevice::raisePropertyChanged(const std::string&amp; prop)
  {
      std::unique_lock&lt;std::mutex&gt; lk (m_d-&gt;mtxClients);
      m_p-&gt;cb(this, prop);  // Invoke callback:  THIS NEVER WORKS*****
  }
  </code></pre>
  <p>Below is the managed client <code>Device</code> class that tries to receive callbacks from the unmanaged <code>GsDevice</code>.</p>
  <p>The .H file</p>
  <pre><code>struct DeviceUnmanagedMembers;  for PIMPL idiom storing unmanaged members.
  
  public ref class Device : public INotifyPropertyChanged
  {
  public:
      virtual event PropertyChangedEventHandler^ PropertyChanged; 
  
  private:
      DeviceUnmanagedMembers* m_p;    // PIMPL idiom
      GCHandle m_callbackHandle;      // Keeps callback locked into one memory address
  
  protected:
      Device(std::shared_ptr&lt;GsDevice&gt; dev);
      delegate void PropertyChangedDelegate(GsDevice* sender, const std::string&amp; propName);
      virtual  void OnPropertyChanged(Gs:Device* pSender, const std::string&amp; propName);
  
  private:
      // I am saving off these as member variables in case it helps .NET keep things
      // alive.  So far, that's not working.
  
      PropertyChangedDelegate^ m_dg;   
      System::IntPtr^          m_ptr;
  };
  </code></pre>
  <p>The .CPP file</p>
  <pre><code>struct DeviceUnmanagedMembers
  {
      std::shared_ptr&lt;GsDevice&gt;            spDevice;  
      DeviceUnmanagedMembers(std::shared_ptr&lt;GsDevice&gt; dev) : spDevice(dev) { }
  };
  
  Device::Device(std::shared_ptr&lt;GsDevice&gt; dev) : m_p(new DeviceUnmanagedMembers(dev))
  {  
      // Get a delegate for our callback function and lock it into memory
  
      auto pcDelegate  = gcnew PropertyChangedDelegate(this, &amp;Device::OnPropertyChanged);
      m_callbackHandle = GCHandle::Alloc(pcDelegate);
      auto callback    = Marshal::GetFunctionPointerForDelegate(pcDelegate);
      auto ptrInt      = callback.ToPointer();
      auto ptrFun      = static_cast&lt;GsDevice::PROPCHANGECALLBACK&gt;(ptrInt); 
  
      // Now hook up to the unamanged client for a callback.  This actually immediately
      // calls me back (to OnPropertyChanged) but all subsequent attempts by the
      // unmanaged object to call me back do nothing.
  
      dev-&gt;setPropertyChangedCallback(ptrFun);
  
      // Save off these items just in case it helps (It doesn't)
  
      m_dg             = pcDelegate;
      m_ptr            = callback;
  }
  
  void Device::OnPropertyChanged(GsDevice* sender, const std::string&amp; propName)
  {    
      // This is the function the unmanaged client is trying to call back.  It works
      // the very first time the client does it but never after.
  
      RaisePropertyChanged(propName);  
  }
  </code></pre>
  <p>Notes:</p>
  <ul>
  <li>Neither <code>Device</code> nor <code>GsDevice</code> object is being cleaned up.  They both still exist because I continue to invoke them with function calls from managed to unmanaged code.</li>
  <li>The unmanaged device keeps trying and failing to call the callback.  No error.  No exception.  It just steps over the call.</li>
  <li>I've compared the exact pointer values of the callback from the first time (when it works) and all subsequent times when it fails.  Its exactly the same.</li>
  <li>The C++/CLI assembly is built with .NET 5.0 and Visual Studio 2019</li>
  <li>The unmanaged C++ code is built with C++17 features enabled (if that matters)</li>
  </ul>