REFIID definition lazarus / 67-Windows ---------------------------------------------------------------------- 440bx · 2025-03-30 17:01 Hello, I just noticed that in redef.inc, the following definitions (among many others) appear: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  type  PIID    = PGUID;  TIID    = TGUID;  REFIID  = TIID;  THANDLE = HANDLE;  In the above a REFIID is the same as a TIID which is the same as a TGUID. However, MSDN defines REFIID as Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  typedef IID* REFIID; which would make a REFIID a _pointer_ to an IID (which is the same as a GUID), therefore a REFIID should be a _pointer_ to a GUID not just equal to a GUID. If that definition is actually incorrect, it is very surprising that it has not been already caught because REFIID is a type that is extensively used in some parts of the Windows API. I also checked the Jwa... definitions and it is defined the same way there but the functions that use a REFIID as a parameter are declared as being var or constref, effecitively passing a pointer to the IID (but those definitions are not parallel to the C definitions.) Note, in other files, the REFIID is passed as a "const" parameter thereby depending on FPC passing a pointer to the REFIID in spite of the fact that the FPC documentation clearly states that, unlike Delphi, "const" does not necessarily imply that the parameter will be passed by reference. Did I miss something or is that definition actually incorrect ? Thank you for your help. ---------------------------------------------------------------------- Remy Lebeau · 2025-03-30 17:41 Quote from: 440bx on March 30, 2025, 07:01:38 pmNote, in other files, the REFIID is passed as a "const" parameter thereby depending on FPC passing a pointer to the REFIID in spite of the fact that the FPC documentation clearly states that, unlike Delphi, "const" does not necessarily imply that the parameter will be passed by reference. In Delphi/FreePascal, it is not uncommon practice to declare a pointer parameter which is not allowed to be nil by its API (and a REFIID is never nil) to be passed as a (const) reference instead to simply user coding. An IID is too big to fit in a single CPU register when passed by value, so passing it by (const) reference will undoubtedly pass it as a pointer. ---------------------------------------------------------------------- 440bx · 2025-03-30 17:57 Thank you for the reply Remy. Quote from: Remy Lebeau on March 30, 2025, 07:41:08 pmAn IID is too big to fit in a single CPU register when passed by value, so passing it by (const) reference will undoubtedly pass it as a pointer. I understand that. My concern is that is if the type REFIID is used in a structure/record then the definition will be incorrect.  In addition to that definition requiring something like "const", "var" or "constref" to be correct, in a record/structure there is no "trick" to make it correct. That definition makes me very uncomfortable because the room for something not working as intended is quite large. ETA: corrected typo ---------------------------------------------------------------------- nanobit · 2025-03-30 18:31 It looks like you have found a real source of bugs. FPC declares a few api functions with riid:REFIID (value parameter) which is wrong. These should declare "const" (possible with "stdcall" convention) or "constref". But less confusing would be TIID (with const, constref) and PIID. ---------------------------------------------------------------------- marcov · 2025-03-30 20:44 IIRC refiid is mostly used in const expressions for interfaces. The swallowing of the pointer is necessary, because Delphi/FPC do interface refcounting automatically. ---------------------------------------------------------------------- 440bx · 2025-03-30 21:34 Quote from: marcov on March 30, 2025, 10:44:34 pmThe swallowing of the pointer is necessary, because Delphi/FPC do interface refcounting automatically. But there are definitions that specify REFIID, without "const", "var", "constref" or some other thing, which will result in a GUID instead of a pointer to a GUID.  Those definitions can't be right.  They violate the definitions given by MS. For instance, in shlobj.pp, there appears the following: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     ICategoryProvider =interface(IUnknown)        ['{9af64809-5864-4c26-a720-c1f78c086ee3}']        function CanCategorizeOnSCID(pscid:pSHCOLUMNID):HRESULT;StdCall;        function GetDefaultCategory(pguid:pGUID; pscid:pSHCOLUMNID):HRESULT;StdCall;        function GetCategoryForSCID(pscid:pSHCOLUMNID; pguid:pGUID):HRESULT;StdCall;      function EnumCategories(out penum:IEnumGUID):HRESULT;StdCall;      function GetCategoryName(pguid:pGUID; pszName:LPWSTR; cch:UINT):HRESULT;StdCall;        function CreateCategory(pguid:pGUID; riid:REFIID; ppv:Ppointer):HRESULT;StdCall;        end; The CreateCategory method takes a _pointer_ to a GUID not a GUID.  The definition is missing a "const", "var", "constref" or any other thing that will cause a pointer to a GUID to be passed and not just a GUID. I haven't tried using that specific method but, it seems rather unlikely that CreateCategory will work as intended.  That's just one instance from a cursory search of where REFIID is used.  There are other instances where the function/method requires a pointer and it is being passed a GUID by value instead. Am I missing something ? ---------------------------------------------------------------------- Remy Lebeau · 2025-03-31 15:36 Quote from: 440bx on March 30, 2025, 07:57:06 pmMy concern is that is if the type REFIID is used in a structure/record then the definition will be incorrect.  True, but in practice does that ever happen?  I'm been doing ActiveX/COM programming for a very long time and I've never seen REFIID used as a data member in a struct/class, only as a function parameter.  This also makes sense because in C++ REFIID can be an actual reference and not a pointer.  If a data member needs to refer to a guid/iid, it is stored either by value, or by pointer using a more appropriate PGUID/PIID type. ---------------------------------------------------------------------- 440bx · 2025-03-31 16:18 Quote from: Remy Lebeau on March 31, 2025, 05:36:54 pmTrue, but in practice does that ever happen?  I'm been doing ActiveX/COM programming for a very long time and I've never seen REFIID used as a data member in a struct/class, only as a function parameter.  I just don't think the possibility of that error should exist because there is no way the compiler could catch it. In the definition of ICategoryProvider I posted above, it seems to me the definition of CreateCategory is incorrect because the second parameter is supposed to be a pointer to a GUID and it is not, it's just a GUID passed by value.  That's the problem with having REFIID incorrectly defined, it causes direct translations of the C prototypes to be incorrect. What are your thoughts on that ? ---------------------------------------------------------------------- Thaddy · 2025-04-01 09:34 Back in the days the design of the Pascal interpretation of the Windows API was defined - partially - like this: 1. if a C x * could be interpreted as a value that could not be nil, use var, not the pointer 2. in any other case respect the pointer The reason is that the guys that developed the Win API for Delphi saw that Delphi could be made safer than the Win API so they payed special attention to the two above rules. The Freepascal Windows API is translated more ad verbatum (to my chagrain, because I think Steve Threfenden was right) but you still can use jwaWindows, which adheres to the above philosophy. Marcov has the opposite opinion with sometimes well worded arguments. And therefor we have the compatibility unit. I hope this gives you some insight how some declarations in Freepascal differ from those in Delphi and why the Delphi declarations differ from Freepascal nad partially why jwaWindows differs from both.... We are talking early mid-90's here. ---------------------------------------------------------------------- marcov · 2025-04-01 09:57 Possibly a GUID is not registerable and then allocated on the local stack and then passed by reference. Just test and check the asm. So probably there should be refuid and realrefuid if you want to fix that (specially to avoid problems when some new architecture's ABI says that a 128-bit parameter can be held in two 64-bit registers). But there seems to be no acute problem. Note that jwa also defines the type pointerless. ---------------------------------------------------------------------- 440bx · 2025-04-01 12:16 Quote from: marcov on April 01, 2025, 11:57:44 amBut there seems to be no acute problem. It would probably be wise for someone well versed in COM to test methods that use a REFIID parameter without a "const", "var" or "constref" to ensure they work properly. I don't think the CreateCategory method will work.  I would test it if I were more adept in COM.  There are other methods declared like that and they should probably be tested too.