/// <summary> /// The CallbackProc. Called by the shell to inform of key property page events. /// </summary> /// <param name="hWnd">The h WND.</param> /// <param name="uMsg">The u MSG.</param> /// <param name="ppsp">The PPSP.</param> /// <returns></returns> private uint CallbackProc(IntPtr hWnd, PSPCB uMsg, ref PROPSHEETPAGE ppsp) { switch (uMsg) { case PSPCB.PSPCB_ADDREF: // Increment the reference count. referenceCount++; break; case PSPCB.PSPCB_RELEASE: // Decrement the reference count. referenceCount--; // If we're down to zero references, cleanup. if (referenceCount == 0) { Cleanup(); } break; case PSPCB.PSPCB_CREATE: // Allow the sheet to be created. return(1); } return(0); }
/// <summary> /// The CallbackProc. Called by the shell to inform of key property page events. /// </summary> /// <param name="hWnd">The h WND.</param> /// <param name="uMsg">The u MSG.</param> /// <param name="ppsp">The PPSP.</param> /// <returns></returns> private uint CallbackProc(IntPtr hWnd, PSPCB uMsg, ref PROPSHEETPAGE ppsp) { switch (uMsg) { case PSPCB.PSPCB_ADDREF: break; case PSPCB.PSPCB_RELEASE: break; case PSPCB.PSPCB_CREATE: // Allow the sheet to be created. return(1); } return(0); }
/// <summary> /// The CallbackProc. Called by the shell to inform of key property page events. /// </summary> /// <param name="hWnd">The h WND.</param> /// <param name="uMsg">The u MSG.</param> /// <param name="ppsp">The PPSP.</param> /// <returns></returns> private uint CallbackProc(IntPtr hWnd, PSPCB uMsg, ref PROPSHEETPAGE ppsp) { // Important: The docs at: https://docs.microsoft.com/en-us/windows/desktop/shell/how-to-register-and-implement-a-property-sheet-handler-for-a-file-type // Imply we *must* set PSP_USEPARENTREF and give access to the parent reference count, to avoid the server being // unloaded while the property sheet is still visible. It is damn near impossible to do this as // the IUnknown of the IShellPropSheetExt is managed by the runtime. Instead, when the internal // reference count increases, we will manually increment the COM server ref count, then release // it when our property sheet tells us we are done. This *appears* to have resolved the lifetime // issues. The theory is that we are using the lifecycle hooks below to manage our IShellPropSheetExt // server ref count and ensure that the shell will not unload it while the property sheet is in use. switch (uMsg) { case PSPCB.PSPCB_ADDREF: { // Increment the internal reference count. Log($"Add Internal Ref {referenceCount} -> {referenceCount + 1}"); referenceCount++; // At this point, increment the IPropSheetShellExt interface reference count, so that the // shell doesn't try and release the server before we are done. var pUnk = Marshal.GetIUnknownForObject(Parent); // i.e. IShellPropSheetExt var newCount = Marshal.AddRef(pUnk); Log($"IShellPropSheetExt: Add Ref {newCount - 1} -> {newCount}"); break; } case PSPCB.PSPCB_RELEASE: { Log($"Release Internal Ref {referenceCount} -> {referenceCount - 1}"); // Decrement the internal reference count. referenceCount--; // If we're down to zero references, cleanup. if (referenceCount == 0) { // The Target is a child of the host window handle, and that is child of the sheet. // So these windows will be destroyed as part of the normal lifecycle. It's important // we *don't* destroy them here or they could be destroyed twice. This is the place // however to free up other resources which might be used by the page. try { Target?.OnRelease(); } catch (Exception exception) { LogError("An exception occured releasing the property page", exception); } } // Balance out the AddRef all from PSPCB_ADDREF by releasing now. var pUnk = Marshal.GetIUnknownForObject(Parent); // i.e. IShellPropSheetExt var newCount = Marshal.Release(pUnk); Log($"IShellPropSheetExt: Release {newCount + 1} -> {newCount}"); break; } case PSPCB.PSPCB_CREATE: Log($"Create Callback"); // Allow the sheet to be created. return(1); } return(0); }
/// <summary> /// The CallbackProc. Called by the shell to inform of key property page events. /// </summary> /// <param name="hWnd">The h WND.</param> /// <param name="uMsg">The u MSG.</param> /// <param name="ppsp">The PPSP.</param> /// <returns></returns> private uint CallbackProc(IntPtr hWnd, PSPCB uMsg, ref PROPSHEETPAGE ppsp) { switch (uMsg) { case PSPCB.PSPCB_ADDREF: // Increment the reference count. referenceCount++; break; case PSPCB.PSPCB_RELEASE: // Decrement the reference count. referenceCount--; // If we're down to zero references, cleanup. if (referenceCount == 0) Cleanup(); break; case PSPCB.PSPCB_CREATE: // Allow the sheet to be created. return 1; } return 0; }
/// <summary> /// The CallbackProc. Called by the shell to inform of key property page events. /// </summary> /// <param name="hWnd">The h WND.</param> /// <param name="uMsg">The u MSG.</param> /// <param name="ppsp">The PPSP.</param> /// <returns></returns> private uint CallbackProc(IntPtr hWnd, PSPCB uMsg, ref PROPSHEETPAGE ppsp) { switch (uMsg) { case PSPCB.PSPCB_ADDREF: break; case PSPCB.PSPCB_RELEASE: break; case PSPCB.PSPCB_CREATE: // Allow the sheet to be created. return 1; } return 0; }