Attila Kovacs 629 Posted February 14, 2022 (edited) this makes an app unpinnable: uses Winapi.Windows, Winapi.ShlObj, Winapi.ShellAPI, Winapi.ActiveX, Winapi.PropSys, Vcl.Forms, .. function MarkWindowAsUnpinnable(Ahwnd: hwnd): HResult; const VARIANT_TRUE = WordBool(-1); PKEY_AppUserModel_PreventPinning: TPropertyKey = (fmtid: '{9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3}'; pid: 9); var pps: IPropertyStore; hr: HResult; v: PROPVARIANT; begin hr := SHGetPropertyStoreForWindow(Ahwnd, IID_IPropertyStore, pointer(pps)); if Succeeded(hr) then begin // pps._AddRef; v.vt := VT_BOOL; v.boolVal := VARIANT_TRUE; hr := pps.SetValue(PKEY_AppUserModel_PreventPinning, v); // pps._Release; end; Result := hr; end; ... Application.CreateForm(TMainForm, MainForm); MarkWindowAsUnpinnable(Application.MainForm.Handle); I'm not sure about the pps._addref and pps._release, I would appreciate some help on that. thx Edited February 14, 2022 by Attila Kovacs Share this post Link to post
qubits 20 Posted February 14, 2022 Don't think it's in there. Property Store Maybe this helps. 1 Share this post Link to post
Anders Melander 1782 Posted February 14, 2022 2 hours ago, Attila Kovacs said: I'm not sure about the pps._addref and pps._release, I would appreciate some help on that. Get rid of the _Release. It's already called implicitly when the interface reference goes out of scope. 1 Share this post Link to post
Attila Kovacs 629 Posted February 14, 2022 (edited) Ok, with the changed signature (out param) following happens: 1. try pps = nil 2. pps.IntfClear on nil 3. SHGetPropertyStoreForWindow => pps.refcount = 1 4. program run 5. finally pps.InfClear end; with var parameter, casting to pointer: 1. try pps = nil 2. SHGetPropertyStoreForWindow => pps.refcount = 1 3. program run 4. finally pps.InfClear end; 1. With my additional addref()/release() the refcount number goes up to 2 but will be released at the end in any way because pps is going out of scope (Am I right?) 2. So I'd think, because pps is a local variable, I don't need any manual intervention to its refcount and therefore I don't understand the signature change to an "out param". I mean, it could be the proper translation, it also looks better without the pointer cast, but I can't see any advantages compared to the already implemented signature. Edited February 14, 2022 by Attila Kovacs Share this post Link to post
Anders Melander 1782 Posted February 14, 2022 I'm not sure I fully understand your explanation. Anyway, now that I think of it you should get rid of both the _AddRef and _Release. The interface being returned by SHGetPropertyStoreForWindow will have a ref count of 1. Your pointer() hard cast ensures that it stays at 1 even though you are storing the reference in a Delphi interface var. When this reference goes out of scope the reference count should become 0. 2 hours ago, Attila Kovacs said: I don't understand the signature change to an "out param" I'm not sure what change you're referencing here. I don't know what the Pascal declaration of SHGetPropertyStoreForWindow looks like but in this case it doesn't really make a difference if ppv is declared as a pointer pointer, an interface or pointer var or out parameter. The semantics are different but the result is the same. I believe the semantics of out best describe what's actually going on here (return of a value with disregard for the current value of the passed var). Look at the declaration (and implementation) of QueryInterface in classes.pas for another way to declare an out parameter returning an arbitrary interface. Share this post Link to post
Attila Kovacs 629 Posted February 14, 2022 (edited) @Anders Melander yes, sorry, forgot to mention, that was under the link from @qubits, where they changed "var pps: pointer" to "out pps: IPropertyStore" Edited February 14, 2022 by Attila Kovacs Share this post Link to post
Anders Melander 1782 Posted February 14, 2022 Okay. "var pps: pointer" matches the documented API (so it's correct) but if you want to use an out parameter instead then the correct declaration would be: function SHGetPropertyStoreForWindow(hwnd: HWND; const riid: TGUID; out ppv): HResult; stdcall; because ppv is documented as: Quote When this function returns, contains the interface pointer requested in riid. This is typically IPropertyStore. which means that it can return another interface if you request that. Note the untyped out parameter, like QueryInterface. Because the parameter is untyped it is your responsibility to pass a var declared as the interface you're requesting. The compiler will not stop you passing in something that doesn't make sense: var Nonsense: IMomsSpaghetti; begin SHGetPropertyStoreForWindow(Handle, IPropertyStore, Nonsense); Nonsense.Vomit; // Boom! end; What is the actual problem you're experiencing, by the way? 1 Share this post Link to post
Attila Kovacs 629 Posted February 14, 2022 (edited) Nothing, I was unsure how to translate it properly without surprises later. I took some C or C# example as a base. Edited February 14, 2022 by Attila Kovacs Share this post Link to post
Remy Lebeau 1394 Posted February 15, 2022 On 2/13/2022 at 4:39 PM, Attila Kovacs said: Application.CreateForm(TMainForm, MainForm); MarkWindowAsUnpinnable(Application.MainForm.Handle); In addition to everthing said about AddRef/Release(), just note that if your Form's window is ever recreated at runtime, you will loose your marking and have to re-apply it on the new window. Best way to avoid that is to have your Form class override the virtual CreateWnd() method to call MarkWindowAsUnpinnable(), don't call it after creating the Form object. 1 Share this post Link to post