www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Recipe and best practice for accessing COM

reply "newToCOM" <new to.COM> writes:
I am trying to use COM to access Windows functionality and APIs.
I have read the interface documentation and some documentation at
MSDN. I have seen the included sample snippet for IHello and the
slides "Modern COM programming in D", but it is still not clear
exactly what to do and what the best practice is.

So, my question is:
I have downloaded Windows SDK and coffimplib. How do I proceed to
access d2d1 and draw a rectangle?

A stepwise description of the recommended procedure is highly
appreciated!
Jul 24 2012
next sibling parent "newToCOM" <new to.COM> writes:
http://forum.dlang.org/thread/fj617q$15qk$1 digitalmars.com

Found this, which may help.
Jul 24 2012
prev sibling next sibling parent reply Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
On 7/24/2012 2:01 PM, newToCOM wrote:
 I am trying to use COM to access Windows functionality and APIs.
 I have read the interface documentation and some documentation at
 MSDN. I have seen the included sample snippet for IHello and the
 slides "Modern COM programming in D", but it is still not clear
 exactly what to do and what the best practice is.

 So, my question is:
 I have downloaded Windows SDK and coffimplib. How do I proceed to
 access d2d1 and draw a rectangle?

 A stepwise description of the recommended procedure is highly
 appreciated!
I made D bindings for d3d11, directwrite, d2d1, and a few other directx APis. They are located at: http://www.dsource.org/projects/bindings/wiki/DirectX The bindings haven't had extensive testing but the bits i've used seem to work correctly (mostly in d3d11) The WindowsApi project is also necessary: http://www.dsource.org/projects/bindings/wiki/WindowsApi
Jul 25 2012
next sibling parent reply "newToCOM" <new to.com> writes:
Thanks for your replies!

I'm trying to accomplish this:
http://msdn.microsoft.com/en-us/library/windows/apps/dd535473.aspx

Using win32 and directx.d2d1, I got this far:

---

...
int WinMain( ... ) { ... }
int myWinMain( ... ) { ... }
LRESULT WndProc ( ... )
{
     ...
     case WM_CREATE:
         D2D1_FACTORY_OPTIONS factoryOptions;
             factoryOptions.debugLevel = 
D2D1_DEBUG_LEVEL.INFORMATION;
         const D2D1_FACTORY_OPTIONS* pfactoryOptions = 
&factoryOptions;
         const IID factory = IID_ID2D1Factory;
         void* ppIFactory;

         HRESULT hr = D2D1CreateFactory(
                 D2D1_FACTORY_TYPE.SINGLE_THREADED,
                 &factory,
                 pfactoryOptions,
                 ppIFactory
                 );
     ...
}

---

I get the following error messages:
- 1 -
function win32.directx.d2d1.D2D1CreateFactory (
     D2D1_FACTORY_TYPE factoryType,
     const(GUID)* riid,
     const(D2D1_FACTORY_OPTIONS*) pFactoryOptions,
     out void* ppIFactory)
is not callable using argument types (
     D2D1_FACTORY_TYPE,
     const(GUID)*,
     const(D2D1_FACTORY_OPTIONS*),
     void*)

- 2 -
cannot implicitly convert expression (& factory)
of type const(GUID)* to const(GUID)*


How should this be done correctly?
How is a rectangle finally drawn?
Sep 02 2012
parent reply "Kagamin" <spam here.lot> writes:
The diagnostic message can definitely be better.
Sep 03 2012
parent reply "newToCOM" <new to.com> writes:
On Monday, 3 September 2012 at 09:10:49 UTC, Kagamin wrote:
 The diagnostic message can definitely be better.
Any idea what's causing the error messages? Why aren't the types matching?
Sep 04 2012
parent "Kagamin" <spam here.lot> writes:
If you have a reduced test case, you can file a diagnostic bug.
Sep 07 2012
prev sibling parent reply "newToCOM" <new to.com> writes:
Still struggling..

test.d:
-----------------------------------
( ... )  /* Other imports */
import win32.directx.d2d1;

alias win32.directx.d2d1.IID IID;
IID IID_ID2D1Factory = { 0x06152247, 0x6F50, 0x465A, [0x92, 0x45, 
0x11, 0x8B, 0xFD, 0x3B, 0x60, 0x07] };

extern (Windows)
int WinMain( ... )
{
     ( ... ) /* Boilerplate code */
}

int myWinMain( ... )
{
     ( ... ) /* Register class, Create window, show window, 
message loop */
}

LRESULT WndProc( ... )
{
     switch (message)
     {
         ( ... ) /* Default and case WM_DESTROY */

         case WM_CREATE:

             // arg2
             REFIID pIID_ID2D1Factory;
             pIID_ID2D1Factory = cast(REFIID)&IID_ID2D1Factory;

             // arg3
             D2D1_FACTORY_OPTIONS factoryOptions;
                 factoryOptions.debugLevel = 
D2D1_DEBUG_LEVEL.INFORMATION;
             const D2D1_FACTORY_OPTIONS* pfactoryOptions = 
&factoryOptions;

             // arg4
             void* pID2D1Factory;


             HRESULT hr = D2D1CreateFactory(
                     D2D1_FACTORY_TYPE.SINGLE_THREADED,
                     pIID_ID2D1Factory,
                     pfactoryOptions,
                     pID2D1Factory
                     );

             writeln(hr);               // Prints 0
             writeln(pID2D1Factory);    // Prints a non-null 
pointer

             // Trying to use the interface
             float dpiX, dpiY;
             pID2D1Factory.GetDesktopDpi(dpiX, dpiY);
             // !!! Error: undefined identifier 'GetDesktopDpi'
             // I thought I had a pointer to the interface and 
could call
             // its methods...

             return 0;

------------------------------

* Coffimplib was used to convert the d2d1.lib from Microsoft 
DirectX SDK (June 2010). The converted d2d1.dll was placed in 
C:\dcode\dlls
* With test.d in C:\dcode, the file was compiled and linked in 
C:\dcode with:
dmd test.d %cd%\dlls\d2d1.lib -I%cd%\dlls\ 
-version=DXSDK_JUNE_2010


- Why is the method identifier undefined?
- Are there any code examples showing the right use of the 
bindings?
Sep 09 2012
parent reply Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
On 9/9/2012 7:30 AM, newToCOM wrote:
 Still struggling..

 test.d:
 -----------------------------------
 ( ... )  /* Other imports */
 import win32.directx.d2d1;

 alias win32.directx.d2d1.IID IID;
 IID IID_ID2D1Factory = { 0x06152247, 0x6F50, 0x465A, [0x92, 0x45, 0x11,
 0x8B, 0xFD, 0x3B, 0x60, 0x07] };

 extern (Windows)
 int WinMain( ... )
 {
      ( ... ) /* Boilerplate code */
 }

 int myWinMain( ... )
 {
      ( ... ) /* Register class, Create window, show window, message loop */
 }

 LRESULT WndProc( ... )
 {
      switch (message)
      {
          ( ... ) /* Default and case WM_DESTROY */

          case WM_CREATE:

              // arg2
              REFIID pIID_ID2D1Factory;
              pIID_ID2D1Factory = cast(REFIID)&IID_ID2D1Factory;

              // arg3
              D2D1_FACTORY_OPTIONS factoryOptions;
                  factoryOptions.debugLevel = D2D1_DEBUG_LEVEL.INFORMATION;
              const D2D1_FACTORY_OPTIONS* pfactoryOptions = &factoryOptions;

              // arg4
              void* pID2D1Factory;


              HRESULT hr = D2D1CreateFactory(
                      D2D1_FACTORY_TYPE.SINGLE_THREADED,
                      pIID_ID2D1Factory,
                      pfactoryOptions,
                      pID2D1Factory
                      );

              writeln(hr);               // Prints 0
              writeln(pID2D1Factory);    // Prints a non-null pointer

              // Trying to use the interface
              float dpiX, dpiY;
              pID2D1Factory.GetDesktopDpi(dpiX, dpiY);
              // !!! Error: undefined identifier 'GetDesktopDpi'
              // I thought I had a pointer to the interface and could call
              // its methods...

              return 0;

 ------------------------------

 * Coffimplib was used to convert the d2d1.lib from Microsoft DirectX SDK
 (June 2010). The converted d2d1.dll was placed in C:\dcode\dlls
 * With test.d in C:\dcode, the file was compiled and linked in C:\dcode
 with:
 dmd test.d %cd%\dlls\d2d1.lib -I%cd%\dlls\ -version=DXSDK_JUNE_2010


 - Why is the method identifier undefined?
 - Are there any code examples showing the right use of the bindings?
In this example the pID2D1Factory is a void*, so it will need a cast to the proper type with a cast(ID2D1Factory) soemtime after the create call; Since this particular API takes an out void* (since it is capable of creating multiple unrelated types), it would need to look something like this: HRESULT hr = D2D1CreateFactory( D2D1_FACTORY_TYPE.SINGLE_THREADED, pIID_ID2D1Factory, pfactoryOptions, pID2D1Factory); if (SUCCEEDED(hr)) { assert(pID2D1Factory !is null); ID2D1Factory factory = cast(ID2D1Factory)pID2D1Factory; factory.GetDesktopDpi(dpiX, dpiY); } I've been super busy at work so haven't had much time to respond to this thread. Technically the API's fourth argument could be rewritten to be an 'out IUnknown', but then you are stuck calling QueryInterface, and back to having the exact same problem with the QueryInterface method.
Sep 09 2012
next sibling parent reply Sean Cavanaugh <WorksOnMyMachine gmail.com> writes:
On 9/9/2012 7:57 AM, Sean Cavanaugh wrote:
 On 9/9/2012 7:30 AM, newToCOM wrote:

 I've been super busy at work so haven't had much time to respond to this
 thread.
I also have a D version of something resembling ATL's CComPtr which I am finally happy enough with to share, that I could post when i get home later tonight. The class is a good argument for keeping the rather esoteric opDot operator, since alias this is extremely dangerous for smart pointer structs in D.
Sep 09 2012
parent "newToCOM" <new to.com> writes:
 I also have a D version of something resembling ATL's CComPtr 
 which I am finally happy enough with to share, that I could 
 post when i get home later tonight.

 The class is a good argument for keeping the rather esoteric 
 opDot operator, since alias this is extremely dangerous for 
 smart pointer structs in D.
That would be great!
Sep 09 2012
prev sibling parent "newToCOM" <new to.com> writes:
 In this example the pID2D1Factory is a void*, so it will need a 
 cast to the proper type with a cast(ID2D1Factory) soemtime 
 after the create call;

 Since this particular API takes an out void* (since it is 
 capable of creating multiple unrelated types), it would need to 
 look something like this:

 HRESULT hr = D2D1CreateFactory(
     D2D1_FACTORY_TYPE.SINGLE_THREADED,
     pIID_ID2D1Factory,
     pfactoryOptions,
     pID2D1Factory);

 if (SUCCEEDED(hr))
 {
 	assert(pID2D1Factory !is null);
 	ID2D1Factory factory = cast(ID2D1Factory)pID2D1Factory;
 	factory.GetDesktopDpi(dpiX, dpiY);
 }


 I've been super busy at work so haven't had much time to 
 respond to this thread.


 Technically the API's fourth argument could be rewritten to be 
 an 'out IUnknown', but then you are stuck calling 
 QueryInterface, and back to having the exact same problem with 
 the QueryInterface method.
Thanks a lot! That solved my issue.
Sep 09 2012
prev sibling parent "Jesse Phillips" <Jessekphillips+D gmail.com> writes:
On Tuesday, 24 July 2012 at 19:01:15 UTC, newToCOM wrote:
 I am trying to use COM to access Windows functionality and APIs.
 I have read the interface documentation and some documentation 
 at
 MSDN. I have seen the included sample snippet for IHello and the
 slides "Modern COM programming in D", but it is still not clear
 exactly what to do and what the best practice is.

 So, my question is:
 I have downloaded Windows SDK and coffimplib. How do I proceed 
 to
 access d2d1 and draw a rectangle?

 A stepwise description of the recommended procedure is highly
 appreciated!
I can't give you much guidance on a step by step type instructions. Haven't done much COM myself. The DX bindings mentioned sound better for what you are asking. For "Modern COM" Juno, and the updated tlbimpd is updated for D2 on https://github.com/JesseKPhillips/Juno-Windows-Class-Library Hope that helps.
Jul 25 2012