www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Use of GUID constants

reply KlausO <oberhofer users.sf.net> writes:
Dear list,

I use DMD 2.070.0 I try to access COM Interfaces via the declarations in 
core.sys.windows.*
I have some problems and maybe someone could give me a usage hint.
Have a look at the following (relatively meaningless) sample program 
which demonstrates the problem.

IMHO the problem is that GUID constants are declared as enums in the
winapi bindings (see src\druntime\import\core\sys\windows\uuid.d).
Within the dclient.d sample which comes with dmd they are explicitely
defined as GUIDs:

GUID IID_IHello  = { 0x00421140, 0, 0, [0xC0, 0, 0, 0, 0, 0, 0, 0x46] };

So maybe they should be declared as "extern GUID ..." because they also 
seem to be defined in windows\lib\uuid.lib which comes with DMD.
What do you think ?

Thanks

-- KlausO


Sample program:


import std.stdio;
import std.utf;
import core.stdc.stdlib;

import core.sys.windows.windows;
import core.sys.windows.com;
import core.sys.windows.objidl;

bool CreateCompoundDoc(const wstring filename)
{
	IStorage storage;

	HRESULT hr = StgCreateDocfile( toUTF16z(filename),
								   STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT | 
STGM_CREATE,
								   0,
								  &storage);

	if (S_OK == hr)
	{
		IUnknown pUnk;

		//
		// Does not compile:
		//
		//  Error: function 
core.sys.windows.unknwn.IUnknown.QueryInterface(const(GUID)* riid, 
void** pvObject) is not callable using argument types (const(GUID), void**)
		//
		hr = storage.QueryInterface(IID_IUnknown, cast(void**)&pUnk);

		//
		// Does not compile either:
		//
		// Error: GUID(0u, cast(ushort)0u, cast(ushort)0u, [cast(ubyte)192u, 
cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)0u, 
cast(ubyte)0u, cast(ubyte)0u, cast(ubyte)70u]) is not an lvalue
		//
		hr = storage.QueryInterface(&IID_IUnknown, cast(void**)&pUnk);
	}
}

int main(string[] argv)
{
	HRESULT hr=CoInitialize(null); // Initialize OLE
	if (FAILED(hr))
	{
		printf("OLE 2 failed to initialize\n");
		return EXIT_FAILURE;
	}

	CreateCompoundDoc("hello.doc");

	// Only call this if CoInitialize worked
	CoUninitialize();
	return EXIT_SUCCESS;
}
Mar 09 2016
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 03/09/2016 10:35 AM, KlausO wrote:

          IUnknown pUnk;

          //
          // Does not compile:
          //
          //  Error: function
 core.sys.windows.unknwn.IUnknown.QueryInterface(const(GUID)* riid,
 void** pvObject) is not callable using argument types (const(GUID), 
void**)
          //
          hr = storage.QueryInterface(IID_IUnknown, cast(void**)&pUnk);
Without any experience with COM or (current) Windows programming, just by looking at that error message, the following may work: IID unknown = IID_IUnknown; // (Apparently, IID is an alias for const(GUID).) storage.QueryInterface(&unknown, /* ... */); Ali
Mar 09 2016
parent reply KlausO <oberhofer users.sf.net> writes:
Ok, but what's the intention behind defining GUIDs as enums in the first 
place ?
Why not defining them as const(GUID) and let the linker sort them out ?
Is there a recommended way to declare/define constants (e.g. as enums or 
consts) ?

In C (separate compilation) they are declared as "EXTERN_C const GUID"
and you use one C file to define this GUIDs for the Linker.

Thanks

-- KlausO

For the record, found two somehow related issues in bugzilla:

https://issues.dlang.org/show_bug.cgi?id=14309
https://issues.dlang.org/show_bug.cgi?id=4092


Am 09.03.2016 um 23:20 schrieb Ali Çehreli:
 On 03/09/2016 10:35 AM, KlausO wrote:

  >          IUnknown pUnk;
  >
  >          //
  >          // Does not compile:
  >          //
  >          //  Error: function
  > core.sys.windows.unknwn.IUnknown.QueryInterface(const(GUID)* riid,
  > void** pvObject) is not callable using argument types (const(GUID),
 void**)
  >          //
  >          hr = storage.QueryInterface(IID_IUnknown, cast(void**)&pUnk);

 Without any experience with COM or (current) Windows programming, just
 by looking at that error message, the following may work:

      IID unknown = IID_IUnknown;
      // (Apparently, IID is an alias for const(GUID).)

      storage.QueryInterface(&unknown, /* ... */);

 Ali
Mar 10 2016
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 10 March 2016 at 10:16:30 UTC, KlausO wrote:
 Ok, but what's the intention behind defining GUIDs as enums in 
 the first place ?
Probably just an implementation error, i.e. someone not fully appreciating how GUIDs are intended to be used.
 Is there a recommended way to declare/define constants (e.g. as 
 enums or consts) ?
Generally, you should use a manifest constant, e.g. enum myConst = 10; Unless you need to take the address, then you should use immutable: immutable myConst = 10; The value of a manifest constant is substituted for the symbol at the point of use and is not stored in the data segment (so has no memory address), but an immutable (or const) variable is stored in the data segment.
Mar 10 2016
parent reply KlausO <oberhofer users.sf.net> writes:
For GUIDs you often have to take the address (e.g. for calls to 
QueryInterface), so I think phobos does not correctly implement this.

In the meantime I took a look at the VisualD project which accesses the 
COM interfaces of visual studio. They solve the problem by using the 
following idiom (see 
https://github.com/D-Programming-Language/visuald/blob/master
sdk/port/servprov.d 
for an example):

const GUID IID_IServiceProvider = IServiceProvider.iid;

interface IServiceProvider : IUnknown
{
	static const GUID iid = { 0x6d5140c1, 0x7436, 0x11ce, [ 0x80, 0x34, 
0x00, 0xaa, 0x00, 0x60, 0x09, 0xfa ] };
public:
	/* [local] */ HRESULT QueryService(
		/* [in] */ in GUID* guidService,
		/* [in] */ in IID* riid,
		/* [out] */ void **ppvObject);
}

If every interface declaration contains the static iid member this 
enables you to provide something similar to the the __uuidof operator in 
VisualC (see https://msdn.microsoft.com/de-de/library/zaah6a61.aspx).

In VisualD something along that line is implemented in the qi_cast 
template (see 
https://github.com/D-Programming-Language/visuald/blob/master/stdext/com.d).


Is the above pair (const GUID and static member) the right way to 
declare this idiom or would the following be better ?
Both compile and seem to be equivalent (in terms of achieving the same 
goal):

enum IID IID_IServiceProvider = { 0x6d5140c1, 0x7436, 0x11ce, [ 0x80, 
0x34, 0x00, 0xaa, 0x00, 0x60, 0x09, 0xfa ] };

interface IServiceProvider : IUnknown
{
	static immutable GUID iid = IID_IServiceProvider;
public:
/* [local] */ HRESULT QueryService(
/* [in] */ in GUID* guidService,
/* [in] */ in IID* riid,
/* [out] */ void **ppvObject);
}

Thanks for your insights

-- KlausO


Am 10.03.2016 um 14:49 schrieb Mike Parker:
 On Thursday, 10 March 2016 at 10:16:30 UTC, KlausO wrote:
 Ok, but what's the intention behind defining GUIDs as enums in the
 first place ?
Probably just an implementation error, i.e. someone not fully appreciating how GUIDs are intended to be used.
 Is there a recommended way to declare/define constants (e.g. as enums
 or consts) ?
Generally, you should use a manifest constant, e.g. enum myConst = 10; Unless you need to take the address, then you should use immutable: immutable myConst = 10; The value of a manifest constant is substituted for the symbol at the point of use and is not stored in the data segment (so has no memory address), but an immutable (or const) variable is stored in the data segment.
Mar 10 2016
parent reply Mike Parker <aldacron gmail.com> writes:
On Thursday, 10 March 2016 at 14:52:16 UTC, KlausO wrote:
 For GUIDs you often have to take the address (e.g. for calls to 
 QueryInterface), so I think phobos does not correctly implement 
 this.
Yes, that was my meaning.
 Is the above pair (const GUID and static member) the right way 
 to declare this idiom or would the following be better ?
 Both compile and seem to be equivalent (in terms of achieving 
 the same goal):

 enum IID IID_IServiceProvider = { 0x6d5140c1, 0x7436, 0x11ce, [ 
 0x80, 0x34, 0x00, 0xaa, 0x00, 0x60, 0x09, 0xfa ] };

 interface IServiceProvider : IUnknown
 {
 	static immutable GUID iid = IID_IServiceProvider;
 public:
 /* [local] */ HRESULT QueryService(
 /* [in] */ in GUID* guidService,
 /* [in] */ in IID* riid,
 /* [out] */ void **ppvObject);
 }
Personally I would just declare one immutable value in module scope and be done with it. It really just doesn't matter. Unless you're following some sort of style guide, personal preference rules the day. I don't know if Rainers has a special reason for what he did with the Visual D code or if it was personal preference. As for Phobos, the Win32 API in Phobos as it stands now was a recent addition. Though it existed as a third-party package for several years, it may still have some kinks to work out and may not follow the Phobos style guide in some places.
Mar 10 2016
parent thedeemon <dlang thedeemon.com> writes:
On Thursday, 10 March 2016 at 15:48:14 UTC, Mike Parker wrote:
 Personally I would just declare one immutable value in module 
 scope and be done with it. It really just doesn't matter. 
 Unless you're following some sort of style guide, personal 
 preference rules the day. I don't know if Rainers has a special 
 reason for what he did with the Visual D code or if it was 
 personal preference.
There is one good reason for doing it VisualD way. It defines and uses smart pointers ComPtr(ISomething) where you can just write auto x = ComPtr!ISomeInterface(someObject); and if someObject has a different COM type this constructor will QueryInterface() for the proper interface, and to do this it needs to know its IID, so a common way to get IID knowing just an interface type is really helpful.
Mar 10 2016
prev sibling parent reply Kagamin <spam here.lot> writes:
On Wednesday, 9 March 2016 at 18:35:31 UTC, KlausO wrote:
 So maybe they should be declared as "extern GUID ..." because 
 they also seem to be defined in windows\lib\uuid.lib which 
 comes with DMD.
Declarations come from mingw and mingw doesn't have uuid.lib: https://issues.dlang.org/show_bug.cgi?id=15482
Mar 11 2016
parent Kagamin <spam here.lot> writes:
Oh, it was 
https://github.com/D-Programming-Language/druntime/pull/1472
Mar 11 2016