April 28, 2017
On Friday, 28 April 2017 at 09:25:31 UTC, John Chapman wrote:
> On Thursday, 27 April 2017 at 20:20:23 UTC, Nierjerson wrote:
>>
>> I think the main issue though, is that I really don't know what is going on when I invoke the PS function. It seems to call the server method that takes the interface and then the server does it's "magic"(which is calling my QueryInterface) but how the implemented QueryInterface is suppose to respond is beyond me... I've tried some based stuff but nothing seem to work. The good news is that it is doing something(calling QueryInterface) which means that the server is at work.
>>
>> Any more ideas?  I think the issue currently is is the QueryInterface(it is simply not doing what it is suppose to). I'll probably have to look at some other implementations to see what is going on.
>
> QueryInterface is COM's version of opCast. It asks if you support the interface represented by an IID (riid). If you don't, then you return E_NOINTERFACE. If you do, then you point the result (pvObject) to yourself and return S_OK. Here's a basic implementation:
>
> extern(Windows)
> HRESULT QueryInterface(IID* riid, void** pvObject) {
>   if (pvObject is null) return E_POINTER;
>   *pvObject = null;
>
>   if (*riid == IID_IUnknown) *pvObject = cast(void*)cast(IUnknown)this;
>   else if (*riid == IID_IDispatch) *pvObject = cast(void*)cast(IDispatch)this;
>   // and so on for all interfaces we support
>
>   if (*pvObject is null) return E_NOINTERFACE;
>   (cast(IUnknown)this).AddRef();
>   return S_OK;
> }
>

Ok, I tried this and returned this but it didn't work. I didn't clal AddRef though, but maybe I was in the right direction but had some other issue.

> AddRef/Release perform the COM object's reference counting, so you should implement them too.
>
> However, I don't understand why your icRBCColor class both implements and encapsulates IDispatch - the generated version cRGBColor from Gen.d just encapsulates it. Why do you need to instantiate an instance of icRGBColor? Can't you just use the rgb1 object you got from the dd.RGB() getter, assign the colour values to its Red, Blue, Green properties as needed, then call the dd.RGB(rgb1) setter? Does that not work?


cRGBColor and any class in Gen.d are not COM interfaces and can't be used. All they do is wrap the dynamic method invocation work that is required to interact with PS.

It may work that I could use them to set the values and then reset the instance but I feel that seems to be a waste. There is no need to really set the object if one is using the property setters. Although my method of creating a "direct" COM interface wrapper(one that inherits from IDispatch and simply delegates the work to the original com) seems to do basically the same, I plan on converting those COM Properties in to D properties and maintain state on both ends that are always in sync(possibly a bit slow, but should be easy to implement and allow one to work with COM in a more D like fashion.

I could, for example, just have those "c" classes inherit from IDispatch directly and then pass on the IDispatch COM calls to the underlying COM interface(which is stored in the c class). That would be a sort of combination of the two methods above and might be better as it avoids actually having to get any of the callback COM stuff working(the stuff I'm having a problem with now). I just wasn't sure if this method would work and didn't want to mess with the gen code too much before I had a better understanding of what is going on.

Regardless, getting the above code to work is still important as it will explain to me how it should work so that I understand for future purposes if this method does not go that route.

Thanks, I'll try to get it to work a again and report back.

April 28, 2017
On Friday, 28 April 2017 at 09:25:31 UTC, John Chapman wrote:
> On Thursday, 27 April 2017 at 20:20:23 UTC, Nierjerson wrote:
>>
>
> QueryInterface is COM's version of opCast. It asks if you support the interface represented by an IID (riid). If you don't, then you return E_NOINTERFACE. If you do, then you point the result (pvObject) to yourself and return S_OK. Here's a basic implementation:
>
> extern(Windows)
> HRESULT QueryInterface(IID* riid, void** pvObject) {
>   if (pvObject is null) return E_POINTER;
>   *pvObject = null;
>
>   if (*riid == IID_IUnknown) *pvObject = cast(void*)cast(IUnknown)this;
>   else if (*riid == IID_IDispatch) *pvObject = cast(void*)cast(IDispatch)this;
>   // and so on for all interfaces we support
>
>   if (*pvObject is null) return E_NOINTERFACE;
>   (cast(IUnknown)this).AddRef();
>   return S_OK;
> }
>

Your code works. I  had something similar but I think I was returning a null pointer on IID_Unknown or something similar. I now get a different error but it is a COM error rather than access violation. (error 80020009)
May 03, 2017
On Friday, 28 April 2017 at 09:25:31 UTC, John Chapman wrote:
> On Thursday, 27 April 2017 at 20:20:23 UTC, Nierjerson wrote:
>>
>> I think the main issue though, is that I really don't know what is going on when I invoke the PS function. It seems to call the server method that takes the interface and then the server does it's "magic"(which is calling my QueryInterface) but how the implemented QueryInterface is suppose to respond is beyond me... I've tried some based stuff but nothing seem to work. The good news is that it is doing something(calling QueryInterface) which means that the server is at work.
>>
>> Any more ideas?  I think the issue currently is is the QueryInterface(it is simply not doing what it is suppose to). I'll probably have to look at some other implementations to see what is going on.
>
> QueryInterface is COM's version of opCast. It asks if you support the interface represented by an IID (riid). If you don't, then you return E_NOINTERFACE. If you do, then you point the result (pvObject) to yourself and return S_OK. Here's a basic implementation:
>
> extern(Windows)
> HRESULT QueryInterface(IID* riid, void** pvObject) {
>   if (pvObject is null) return E_POINTER;
>   *pvObject = null;
>
>   if (*riid == IID_IUnknown) *pvObject = cast(void*)cast(IUnknown)this;
>   else if (*riid == IID_IDispatch) *pvObject = cast(void*)cast(IDispatch)this;
>   // and so on for all interfaces we support
>
>   if (*pvObject is null) return E_NOINTERFACE;
>   (cast(IUnknown)this).AddRef();
>   return S_OK;
> }
>
> AddRef/Release perform the COM object's reference counting, so you should implement them too.
>


I wrapped the COM interface that is returned by PS and the queryInterface works and everything passes(as it should) but when I use your query interface it results in the COM error specified. Seems that the QueryInterface code is not 100% correct or something else is going on.

What I notices is that when PS's QueryInterface routine is used, it is called only 3 times(queries 3 interfaces like IUnknown, etc) while when I use your code about 10 interfaces are queried(including those 3 from PS).

PS's RGB QueryInterface

QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19F178(Object)
QueryInterface Called: ECC8691B-C1DB-4DC0-855E-65F6C551AF49(GUID), 19F124(Object)
QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19EFE8(Object)
main.icRGBColor.Release



Yours

QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19F178(Object)        Not Supported
QueryInterface Called: ECC8691B-C1DB-4DC0-855E-65F6C551AF49(GUID), 19F124(Object)       Not Supported
QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19EFE8(Object)        Not Supported
QueryInterface Called: 0000001B-0000-0000-C00-000000000046(GUID), 19F00C(Object)        Not Supported
QueryInterface Called: 00000000-0000-0000-C00-000000000046(GUID), 19F040(Object)        IUnknown Supported
main.icRGBColor.AddRef
QueryInterface Called: 00000018-0000-0000-C00-000000000046(GUID), 19EF1C(Object)        Not Supported
QueryInterface Called: 334D391F-0E79-3B15-C9FF-EAC65DD07C42(GUID), 19EEF4(Object)       Not Supported
QueryInterface Called: 00000040-0000-0000-C00-000000000046(GUID), 19EF30(Object)        Not Supported
QueryInterface Called: 334D391F-0E79-3B15-C9FF-EAC65DD07C42(GUID), 19EEF4(Object)       Not Supported
QueryInterface Called: 94EA2B94-E9CC-49E0-C0FF-EE64CA8F5B90(GUID), 19EF34(Object)       Not Supported
QueryInterface Called: 334D391F-0E79-3B15-C9FF-EAC65DD07C42(GUID), 19EEF4(Object)       Not Supported
QueryInterface Called: 77DD1250-139C-2BC3-BD95-900ACED61BE5(GUID), 19EF2C(Object)       Not Supported
QueryInterface Called: 334D391F-0E79-3B15-C9FF-EAC65DD07C42(GUID), 19EEF4(Object)       Not Supported
QueryInterface Called: BFD60505-5A1F-4E41-88BA-A6FB07202DA9(GUID), 19EF28(Object)       Not Supported
QueryInterface Called: 334D391F-0E79-3B15-C9FF-EAC65DD07C42(GUID), 19EEF4(Object)       Not Supported
QueryInterface Called: 03FB5C57-D534-45F5-A1F4-D39556983875(GUID), 19EF24(Object)       Not Supported
QueryInterface Called: 334D391F-0E79-3B15-C9FF-EAC65DD07C42(GUID), 19EEF4(Object)       Not Supported
QueryInterface Called: 2C258AE7-50DC-49FF-9D1D-2ECB9A52CDD7(GUID), 19EF20(Object)       Not Supported
QueryInterface Called: 00000019-0000-0000-C00-000000000046(GUID), 2B5A3C0(Object)       Not Supported
QueryInterface Called: 4C1E39E1-E3E3-4296-AA86-EC938D896E92(GUID), 19EF18(Object)       Not Supported
main.icRGBColor.Release
QueryInterface Called: 00020400-0000-0000-C00-000000000046(GUID), 19ED8C(Object)        IDispatch Supported
main.icRGBColor.AddRef
QueryInterface Called: F37B4894-3ED2-48AF-AD38-BB1B27E93869(GUID), 2D3EAAC(Object)      Not Supported
QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19EFE8(Object)



I don't know if things are passed off to another query method or what. The query interface I use is


	// IUnknown
	int QueryInterface(const(GUID)* riid, void** pvObject)
	{
		write("QueryInterface Called: ", Guid2Str(*riid), "(GUID), ", pvObject, "(Object)");
		//version(wrap)
		{
			writeln();

			return rgb.iDispatch.QueryInterface(riid, pvObject);
		}

		// Always set out parameter to NULL, validating it first.
		if (pvObject is null) return E_POINTER;
		*pvObject = null;

		if (*riid == IID_IUnknown)
		{
			*pvObject = cast(void*)cast(IUnknown)this;
			writeln("\tIUnknown Supported");
		}
		else if (*riid == IID_IDispatch)
		{
			*pvObject = cast(void*)cast(IDispatch)this;
			writeln("\tIDispatch Supported");
		}

	
		// and so on for all interfaces we support
		
		if (*pvObject is null)
		{
			writeln("\tNot Supported");
			return E_NOINTERFACE;
		}

		//(cast(IUnknown)this).AddRef();
		return S_OK;

	}


Any ideas where to proceed?
May 06, 2017
I've modified the code and it seems to call GetTypeInfo but the values passed seem frivolous. The modified code I'm using is below. Maybe we can get this to work? I'm interested in a photoshop interop too. Seems like it should be rather trivial to get to work but things don't add up ;/






module main;
import std.stdio;

import core.sys.windows.winnt;

import Gen;

string Guid2Str(GUID guid)
{
	import std.conv, std.string, std.algorithm;
	auto bytes = cast(byte[16])guid;
	auto a = to!string(*(cast(DWORD*)(bytes[0..4])), 16).rightJustify(8, '0');
	auto b = to!string(*(cast(WORD*)(bytes[4..6])), 16).rightJustify(4, '0');
	auto c = to!string(*(cast(WORD*)(bytes[6..8])), 16).rightJustify(4, '0');
	auto d = to!string(*(cast(BYTE*)(bytes[8..9])), 16).rightJustify(1, '0');
	auto e = to!string(*(cast(BYTE*)(bytes[9..10])), 16).rightJustify(1, '0');
	auto q = bytes[10..16];
	reverse(q);
	auto f = to!string(*(cast(long*)(q)) & 0xFFFFFFFFFFFF, 16).rightJustify(12, '0');

	auto ret = a~"-"~b~"-"~c~"-"~d~e~"-"~f;
	return ret;
}


// Creates a guid from a guid hex string. e.g., "B3C35001-B625-48D7-9D3B-C9D66D9CF5F1" -> {0xC09F153E, 0xDFF7, 0x4EFF, [0xA5, 0x70, 0xAF, 0x82, 0xC1, 0xA5, 0xA2, 0xA8]}
GUID GuidN(string str)
{
	// 3   2   1        5E5C5D5C5B5A4L4H
	// 4dc0c1dbecc8691b 49af51c5f6655e85
	//DEFINE_GUID(IID_INoMarshal,0xecc8691b,0xc1db,0x4dc0,0x85,0x5e,0x65,0xf6,0xc5,0x51,0xaf,0x49);
	//MIDL_INTERFACE("ecc8691b-c1db-4dc0-855e-65f6c551af49")

	import std.string;
	GUID guid;
	auto bytes = cast(byte*)(cast(void*)&guid);
	if (str == "") return IID.init;
	auto parts = split(str, "-"); auto p3 = parts[3].rightJustify(4, '0'); auto p4 = parts[4].rightJustify(12, '0');

	*(cast(long*)(bytes[0..8])) = to!long(parts[2].rightJustify(4, '0')~parts[1].rightJustify(4, '0')~parts[0].rightJustify(8, '0'), 16);	
	*(cast(long*)(bytes[8..16])) = to!long(p4[10..$]~p4[8..10]~p4[6..8]~p4[4..6]~p4[2..4]~p4[0..2]~p3[2..$]~p3[0..2], 16);

	return guid;
}

int main(string[] argv)
{
	

	// Issue QueryInterface seems to have the issue(not the same behavior as what is returned by the PS COM Interface)
	
	auto x = new cApplication();				
	auto x1 = x.Path();
	auto x2 = x.Name();	
	auto x3 = x.SystemInformation();
	auto x4 = x.Version();
	auto e = x.RecentFiles();
	auto g = x.DisplayDialogs();
	auto x5 = x.Documents();
	auto x6 = x5.Count();	


	auto dd = x.ForegroundColor();
	auto __red = dd.RGB().Red();
	auto __green = dd.RGB().Green();
	auto __blue = dd.RGB().Blue();

	GUID clsID = Guid!("4549DC9D-8A15-46F0-A0ED-7DB9C02FCB18");
	GUID iID = Guid!("45F1195F-3554-4B3F-A00A-E1D189C0DC3E");
	auto rgb1 = dd.RGB();
	auto clsids = Guid2Str(rgb1.clsID);
	auto rgb2 = new icRGBColor();
	rgb2.iDispatch = rgb2;
	//auto rgb = cast(icRGBColor)&rgb2;
	//dd.RGB(cast(cRGBColor)(cast(void*)rgb));
	//dd.RGB(cast(icRGBColor)(cast(void*)rgb));


	cSolidColor.RGBSet = &RGB;
	auto rgb = new icRGBColor();
	//auto rgb = cast(icRGBColor)(cast(void*)dd.RGB());
	dd.RGB(rgb, rgb1);
	//dd.RGB2(rgb1);

    return 0;
}


void RGB(icRGBColor ic, cRGBColor c, cSolidColor s)
{
	GUID clsIDa = Guid!("AEADF007-9EE5-41D7-8CB1-AB5F353D1151");
	GUID iIDa = Guid!("D2D1665E-C1B9-4CA0-8AC9-529F6A3D9002");
	ic.iDispatch = s.iDispatch;
	ic.rgb = c;

	import main;
	EXCEPINFO exception;
	uint argErr = 0;
	auto iidNULL = IID_NULL;
	auto RT = new VARIANT();
	VARIANT[1] paramVars;
	DISPPARAMS params = {rgvarg: paramVars.ptr, cArgs: 1, cNamedArgs: 0};
	auto ID = s.COMMethodIDs[`RGB`];
	paramVars[0].punkVal = ic; paramVars[0].vt = VARENUM.VT_DISPATCH; scope(exit) VariantClear(&paramVars[0]);
	DISPID mydispid = DISPID_PROPERTYPUT;
	params.rgdispidNamedArgs = &mydispid;
	params.cNamedArgs = 1;
	writeln("-----------");
	auto res = s.iDispatch.Invoke(cast(int)ID, &iidNULL, 0, DISPATCH_PROPERTYPUT, &params, cast(VARIANT*)RT, &exception, &argErr);
	assert(res == S_OK, `Could not invoke COM Function cSolidColor.RGB. Error `~to!string(res, 16));

}






//version = wrap;


import std.conv, core.sys.windows.windows, core.sys.windows.com, core.sys.windows.wtypes, core.sys.windows.basetyps, core.sys.windows.unknwn, core.sys.windows.oaidl;

public class icRGBColor : IDispatch
{


	import std.conv, core.sys.windows.windows, core.sys.windows.com, core.sys.windows.wtypes, core.sys.windows.basetyps, core.sys.windows.unknwn, core.sys.windows.oaidl;
	public IDispatch iDispatch = null;
	int RefCount = 0;
	cRGBColor rgb;

version(all)
{
	void printFunc(string S = __FUNCTION__)()
	{		
		writeln(S);	
	}

	double Red()
	{ 	
		
		printFunc();
		version(wrap)
			return rgb.Red();
		return 0;
	}

	void Red(double rhs)
	{
		printFunc();
		version(wrap)
			rgb.Red(rhs);
	}

	double Green()
	{

		printFunc();
		version(wrap)
			return rgb.Green();
		return 0;
	}

	void Green(double rhs)
	{


		printFunc();
		version(wrap)
			rgb.Green(rhs);
	}

	double Blue()
	{


		printFunc();
		version(wrap)
			return rgb.Blue();
		return 0;
	}

	void Blue(double rhs)
	{


		printFunc();
		version(wrap)
			rgb.Blue();
	}

	BSTR HexValue()
	{


		printFunc();
		version(wrap)
			return rgb.HexValue();
		return cast(wchar*)(""w.ptr);
	}

	void HexValue(BSTR rhs)
	{


		printFunc();
		version(wrap)
			rgb.HexValue(rhs);
	}

	cApplication Application()
	{

		printFunc();
		return null;
	}
}


/*
	QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19F178(Object), 0(Ret)
	QueryInterface Called: ECC8691B-C1DB-4DC0-855E-65F6C551AF49(GUID), 19F124(Object), 80004002(Ret)
	QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19EFE8(Object), 0(Ret)

	QueryInterface Called: 00000003-0000-0000-C00-000000000046(GUID), 19F178(Object)
	main.icRGBColor.GetTypeInfo
*/		

	// IUnknown
	int QueryInterface(const(GUID)* riid, void** pvObject)
	{
		write("QueryInterface Called: ", Guid2Str(*riid), "(GUID), ", pvObject, "(Object)");
		version(wrap)
		{			
			auto res = rgb.iDispatch.QueryInterface(riid, pvObject);
			writeln(", ", to!string(res, 16), "(Ret)");
			return res;
		}

		auto guids = [["00000003-0000-0000-C00-000000000046", "0"], ["ECC8691B-C1DB-4DC0-855E-65F6C551AF49", "0x80004002"]];
		
		foreach(g; guids)
		{
			if (Guid2Str(*riid) == g[0])
			{
				void **pv;
				auto guid = GuidN(g[0]);

				auto x = rgb.iDispatch.QueryInterface(&guid, pv);
				auto res3 = to!int(g[1], 16);
				

				// Always set out parameter to NULL, validating it first.
				if (pvObject is null)
					return E_POINTER;
				*pvObject = null;

				*pvObject = cast(void*)cast(IUnknown)this;

				writeln();
				return res3;

			}
		}

		/*
		auto ress = iDispatch.QueryInterface(riid, pvObject);
		writeln("(", ress, ")");
		return ress;
		*/

		// Always set out parameter to NULL, validating it first.
		if (pvObject is null) return E_POINTER;
		*pvObject = null;

		if (*riid == IID_IUnknown)
		{
			*pvObject = cast(void*)cast(IUnknown)this;
			writeln("\tIUnknown Supported");
		}
		else if (*riid == IID_IDispatch)
		{
			*pvObject = cast(void*)cast(IDispatch)this;
			writeln("\tIDispatch Supported");
		}

	
		// and so on for all interfaces we support
	
		
		if (*pvObject is null)
		{
			writeln("\tNot Supported");
			return E_NOINTERFACE;
		}

		//(cast(IUnknown)this).AddRef();
		return S_OK;

	}


version(all)
{
	uint AddRef()
	{
		
		printFunc();
		version(wrap)
			return rgb.iDispatch.AddRef();
		return ++RefCount;
	}

	uint Release()
	{


		printFunc();
		version(wrap)
			return rgb.iDispatch.Release();
		return --RefCount;
	}



	// IDispatch
	int GetTypeInfoCount(uint* x)
	{

		printFunc();
		auto res = rgb.iDispatch.GetTypeInfoCount(x);
		writeln(res);
		version(wrap)
			return rgb.iDispatch.GetTypeInfoCount(x);
		return res;					
		return 0;
	}
}


	LPTYPEINFO m_ptinfoEnglish;
	LPTYPEINFO m_ptinfoGerman;
	static const auto LCID_ENGLISH = MAKELCID(MAKELANGID(0x09, 0x01), SORT_DEFAULT);
	static const auto LCID_GERMAN = MAKELCID(MAKELANGID(0x07, 0x01), SORT_DEFAULT);

	int GetTypeInfo(uint iTInfo, LCID lcid, LPTYPEINFO* ppTInfo)
	{
		import std.c.stdlib;

		auto xxx = LCID_ENGLISH;
		LPTYPEINFO ptinfo;

		//if (ppTInfo == NULL)
			//return E_INVALIDARG;

//		*ppTInfo = NULL;

//		if(iTInfo != 0)
			//return DISP_E_BADINDEX;

		if(lcid == LOCALE_SYSTEM_DEFAULT || lcid == 0)
			lcid = GetSystemDefaultLCID();

		if(lcid == LOCALE_USER_DEFAULT)
			lcid = GetUserDefaultLCID();

		switch(lcid)
		{
			case LCID_GERMAN:
				ptinfo = m_ptinfoGerman;
				break;

			case LCID_ENGLISH:
				ptinfo = m_ptinfoEnglish;
				break;

			default:
				return DISP_E_UNKNOWNLCID;
		}

		ptinfo.AddRef();
		*ppTInfo = ptinfo;
		return NOERROR;

		//m_ptinfo.AddRef();      // AddRef and return pointer to cached
		// typeinfo for this object.
		//*ppTInfo = m_ptinfo;

		return NOERROR;

		ITypeInfo t;
		auto p = malloc(ITypeInfo.sizeof);
		ppTInfo = &t;
		printFunc();
		//iTInfo  = 0; lcid = 0;
		auto res = rgb.iDispatch.GetTypeInfo(iTInfo, lcid, cast(ITypeInfo*)p);
		ppTInfo = cast(ITypeInfo*)p;
		writeln(res);
		version(wrap)
			return rgb.iDispatch.GetTypeInfo(a,b,c);
		return res;
		return 0;
	}

version(all)
{
	int GetIDsOfNames(const(GUID)* a, wchar** b, uint c, uint d, int* e)
	{


		printFunc();
		version(wrap)
			return rgb.iDispatch.GetIDsOfNames(a,b,c,d,e);
		return 0;
	}

	int Invoke(int a, const(GUID)* b, uint c, ushort d, DISPPARAMS* e, VARIANT* f, EXCEPINFO* g, uint* h)
	{


		printFunc();
		version(wrap)
			return rgb.iDispatch.Invoke(a,b,c,d,e,f,g,h);
		return 0;
	}







	// cRGBColor
	public this()
	{
		printFunc();
	}

}
}




1 2
Next ›   Last »