Photoshop programming
thedeemon via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Mon Feb 15 04:18:47 PST 2016
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.
More information about the Digitalmars-d-learn
mailing list