www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Photoshop programming

reply Patience <Patience.Is Virtue.Life> writes:
Photoshop has the ability to be controlled by scripts and 
programming languages. For example, C# can be used to access 
photoshop by adding the appropriate reference and using 
directives. I believe it is COM based but I am not totally sure.

I've tried reading the docs but it's not making much sense.

http://www.lunesu.com/uploads/ModernCOMProgramminginD.pdf

links at the bottom are down.

It says one has to create a wrapper, but then talks like it can 
be done automatically. I assume that is what project does? But 
then one has to create an idl, not sure what that is ;\

Any info on how to do this stuff properly?
Feb 14 2016
parent thedeemon <dlang thedeemon.com> writes:
On Sunday, 14 February 2016 at 09:48:54 UTC, Patience wrote:
 Photoshop has the ability to be controlled by scripts and 
 programming languages. For example, C# can be used to access 
 photoshop by adding the appropriate reference and using 
 directives. I believe it is COM based but I am not totally sure.

 I've tried reading the docs but it's not making much sense.

 http://www.lunesu.com/uploads/ModernCOMProgramminginD.pdf

 links at the bottom are down.

 It says one has to create a wrapper, but then talks like it can 
 be done automatically. I assume that is what project does? But 
 then one has to create an idl, not sure what that is ;\

 Any info on how to do this stuff properly?
Unfortunately the project mentioned in that presentation seems to be unavailable. In order to work with COM objects from D you need to have definitions of their interfaces translated to D. Initially they are often described in IDL files (Interface Definition Language) or TLB files (type library), and there are nice tools like tlb2idl.exe and idl2d.exe that can convert them to .d files. You can find them in the VisualD project tree. And if original definitions are in C++, in many cases Ctrl-C-Ctrl-V is all you need to convert to D. ;) Then you may work with them directly or you might want a wrapper that will call Release() for you when appropriate. I'm using a wrapper like this: https://gist.github.com/thedeemon/3c2989b76004fafe9aa0 Originally taken from VisualD source but then modified to my needs. For example, I need to use IAMVfwCompressDialogs interface from Microsoft SDK. It's defined in axextend.idl file in the SDK and looks like this: [ object, local, uuid(D8D715A3-6E5E-11D0-B3F0-00AA003761C5), pointer_default(unique) ] interface IAMVfwCompressDialogs : IUnknown { // Bring up a dialog for this codec HRESULT ShowDialog( [in] int iDialog, // VfwCompressDialogs enum [in] HWND hwnd ); // Calls ICGetState and gives you the result HRESULT GetState( [out, size_is(*pcbState), annotation("__out_bcount_part(*pcbState, *pcbState)")] LPVOID pState, [in, out, annotation("__inout")] int *pcbState ); // Calls ICSetState HRESULT SetState( [in, size_is(cbState), annotation("__in_bcount(cbState)")] LPVOID pState, [in] int cbState ); // Send a codec specific message HRESULT SendDriverMessage( [in] int uMsg, [in] long dw1, [in] long dw2 ); } I use idl2d.exe and get following D code (minus some comments): const GUID IID_IAMVfwCompressDialogs = IAMVfwCompressDialogs.iid; interface IAMVfwCompressDialogs : IUnknown { static const GUID iid = { 0xD8D715A3,0x6E5E,0x11D0,[ 0xB3,0xF0,0x00,0xAA,0x00,0x37,0x61,0xC5 ] }; // Bring up a dialog for this codec HRESULT ShowDialog( in int iDialog, // VfwCompressDialogs enum in HWND hwnd ); // Calls ICGetState and gives you the result HRESULT GetState( LPVOID pState, int *pcbState ); // Calls ICSetState HRESULT SetState( in LPVOID pState, in int cbState ); // Send a codec specific message HRESULT SendDriverMessage( in int uMsg, in int dw1, in int dw2 ); } Then in my D code I just write enum { VfwCompressDialog_Config = 0x01, VfwCompressDialog_About = 0x02 } ... auto vfw = ComPtr!IAMVfwCompressDialogs(pg.vcodec); if (vfw) vfw.ShowDialog(VfwCompressDialog_Config, hwnd); where pg.vcodec is my variable of type ComPtr!IBaseFilter I created earlier. Here the ComPtr wrapper uses internally QueryInterface() to get pointer to desired interface, and when my vfw variable goes out of scope, Release() will be called automatically. Moreover, if ShowDialog here returns a bad value a COMException will be generated automatically (this is my own addition to ComPtr behavior). To create some COM object in the first place, knowing its CLSID, I do like this: auto CLSID_NullRenderer = Guid!("C1F400A4-3F08-11D3-9F0B-006008039E37"); //qedit.dll auto pNullRendr = ComPtr!IBaseFilter(CLSID_NullRenderer, "null renderer"); Here IBaseFilter is just some COM interface from Microsoft SDK I need. ComPtr constructor understands what to do depending on whether it's given some GUID or a pointer to some object. Moral of this story, if you have the COM interfaces defined in D, you can have wrappers to do resource management, interface querying and error checking automatically, but first you need to translate (often using automatic tools) the interfaces.
Feb 15 2016