www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Need help on COM Programming Problem

reply Steve Myers <zzmyers gmail.com> writes:
I have been using D 1.0 for a while (currently using 1.028), mostly in Linux.
Recently I have moved to Windows as forced by necessity of having to tie in to
some custom OCX controls provided by a hardware manufacturer. I have been
almost beating my brains out trying to get the COM interface to work correctly
in D. The provider of the OCX gives a sample program in Visual C# which works
fine, but when I use it in D, everything seems to set up properly and then when
I call methods of the COM Interface, it either silently fails (no errors
reported) or it bombs out with an Access Violation. 

Here is a simple program in which I call 2 methods of the object and they
appear to work (no error), but they actually don't do anything.

---------------------------
module test;

import std.c.stdio, std.c.stdlib, std.c.windows.windows, std.c.windows.com;
import local.utils;

GUID IID_ITracker = {0x83d5a123, 0x6857, 0x423b, [0x94, 0x55, 0x8b, 0x89, 0xd5,
0x32, 0xeb, 0xf9]};
GUID CLSID_Tracker = {0x43f7fc01, 0xe47e, 0x473c, [0xaa, 0xdd, 0xe7, 0xe5,
0xd2, 0xe0, 0xb8, 0x41]};

interface ITracker : IUnknown 
{
        extern(Windows):
        int ReadConfig(wchar* filePath);
        int WriteConfig(wchar* filePath);
}

int main()
{
        DWORD       dwVer;
        HRESULT     hr;
        ITracker    pITracker;
        
        hr=CoInitialize(null);          //Initialize OLE
        if (FAILED(hr))
        {       printf("OLE 2 failed to initialize\n");
                return EXIT_FAILURE;
        }
        printf("OLE 2 initialized\n");
        
        hr=CoCreateInstance(&CLSID_Tracker, null, CLSCTX_ALL, &IID_ITracker,
&pITracker);
        if (FAILED(hr))
        {   printf("Failed to create object x%x\n",hr);
        }
        else
        {       int g, status;
                printf("Object created, calling ITracker.ReadConfig(), ITracker
= %p\n", pITracker);
                status =
pITracker.ReadConfig(fromString(`"C:\TD\Test\trackerconfig.txt"`));
                if (status < 0)
                        printf("Failed! Error = %d\n", status);
                printf("Calling ITracker.WriteConfig(), ITracker = %p\n",
pITracker);
                status = pITracker.ReadConfig(toBSTR(`E:\trackerconfig.txt`));
                if (status < 0)
                        printf("Failed! Error = %d\n", status);
                fflush(stdout);
                pITracker.Release();
        }
        CoUninitialize();
        return EXIT_SUCCESS;
}
--------------
I based this off the sample provided with DMD. I have tried to get this working
with Juno, DWin and the basic Phobos libraries to no avail. I am certain I must
be doing something really stupid, but for the life of me cannot figure it out.
I don't post problems often as I can usually find my answers though Google, but
this one has me stumped. 

If someone can please point out what I am doing wrong, I would be eternally
grateful.

Steve
Jul 24 2008
parent reply "Koroskin Denis" <2korden gmail.com> writes:
On Fri, 25 Jul 2008 08:38:11 +0400, Steve Myers <zzmyers gmail.com> wrote:

 I have been using D 1.0 for a while (currently using 1.028), mostly in  
 Linux. Recently I have moved to Windows as forced by necessity of having  
 to tie in to some custom OCX controls provided by a hardware  
 manufacturer. I have been almost beating my brains out trying to get the  
 COM interface to work correctly in D. The provider of the OCX gives a  
 sample program in Visual C# which works fine, but when I use it in D,  
 everything seems to set up properly and then when I call methods of the  
 COM Interface, it either silently fails (no errors reported) or it bombs  
 out with an Access Violation.

 Here is a simple program in which I call 2 methods of the object and  
 they appear to work (no error), but they actually don't do anything.

 ---------------------------
 module test;

 import std.c.stdio, std.c.stdlib, std.c.windows.windows,  
 std.c.windows.com;
 import local.utils;

 GUID IID_ITracker = {0x83d5a123, 0x6857, 0x423b, [0x94, 0x55, 0x8b,  
 0x89, 0xd5, 0x32, 0xeb, 0xf9]};
 GUID CLSID_Tracker = {0x43f7fc01, 0xe47e, 0x473c, [0xaa, 0xdd, 0xe7,  
 0xe5, 0xd2, 0xe0, 0xb8, 0x41]};

 interface ITracker : IUnknown
 {
         extern(Windows):
         int ReadConfig(wchar* filePath);
         int WriteConfig(wchar* filePath);
 }

 int main()
 {
         DWORD       dwVer;
         HRESULT     hr;
         ITracker    pITracker;
        hr=CoInitialize(null);          //Initialize OLE
         if (FAILED(hr))
         {       printf("OLE 2 failed to initialize\n");
                 return EXIT_FAILURE;
         }
         printf("OLE 2 initialized\n");
        hr=CoCreateInstance(&CLSID_Tracker, null, CLSCTX_ALL,  
 &IID_ITracker, &pITracker);
         if (FAILED(hr))
         {   printf("Failed to create object x%x\n",hr);
         }
         else
         {       int g, status;
                 printf("Object created, calling ITracker.ReadConfig(),  
 ITracker = %p\n", pITracker);
                 status =  
 pITracker.ReadConfig(fromString(`"C:\TD\Test\trackerconfig.txt"`));
                 if (status < 0)
                         printf("Failed! Error = %d\n", status);
                 printf("Calling ITracker.WriteConfig(), ITracker =  
 %p\n", pITracker);
                 status =  
 pITracker.ReadConfig(toBSTR(`E:\trackerconfig.txt`));
                 if (status < 0)
                         printf("Failed! Error = %d\n", status);
                 fflush(stdout);
                 pITracker.Release();
         }
         CoUninitialize();
         return EXIT_SUCCESS;
 }
 --------------
 I based this off the sample provided with DMD. I have tried to get this  
 working with Juno, DWin and the basic Phobos libraries to no avail. I am  
 certain I must be doing something really stupid, but for the life of me  
 cannot figure it out. I don't post problems often as I can usually find  
 my answers though Google, but this one has me stumped.

 If someone can please point out what I am doing wrong, I would be  
 eternally grateful.

 Steve

Put some logging or debug step-by-step to understand at what line does the access violation take place. Besides, try using `"C:\TD\Test\trackerconfig.txt"`w or toUTF16z(someFileName) instead of fromString(`"C:\TD\Test\trackerconfig.txt"`). Hope this helps.
Jul 25 2008
parent Steve Myers <zzmyers gmail.com> writes:
Koroskin Denis Wrote:

 On Fri, 25 Jul 2008 08:38:11 +0400, Steve Myers <zzmyers gmail.com> wrote:
 
 I have been using D 1.0 for a while (currently using 1.028), mostly in  
 Linux. Recently I have moved to Windows as forced by necessity of having  
 to tie in to some custom OCX controls provided by a hardware  
 manufacturer. I have been almost beating my brains out trying to get the  
 COM interface to work correctly in D. The provider of the OCX gives a  
 sample program in Visual C# which works fine, but when I use it in D,  
 everything seems to set up properly and then when I call methods of the  
 COM Interface, it either silently fails (no errors reported) or it bombs  
 out with an Access Violation.

 Here is a simple program in which I call 2 methods of the object and  
 they appear to work (no error), but they actually don't do anything.

 ---------------------------
 module test;

 import std.c.stdio, std.c.stdlib, std.c.windows.windows,  
 std.c.windows.com;
 import local.utils;

 GUID IID_ITracker = {0x83d5a123, 0x6857, 0x423b, [0x94, 0x55, 0x8b,  
 0x89, 0xd5, 0x32, 0xeb, 0xf9]};
 GUID CLSID_Tracker = {0x43f7fc01, 0xe47e, 0x473c, [0xaa, 0xdd, 0xe7,  
 0xe5, 0xd2, 0xe0, 0xb8, 0x41]};

 interface ITracker : IUnknown
 {
         extern(Windows):
         int ReadConfig(wchar* filePath);
         int WriteConfig(wchar* filePath);
 }

 int main()
 {
         DWORD       dwVer;
         HRESULT     hr;
         ITracker    pITracker;
        hr=CoInitialize(null);          //Initialize OLE
         if (FAILED(hr))
         {       printf("OLE 2 failed to initialize\n");
                 return EXIT_FAILURE;
         }
         printf("OLE 2 initialized\n");
        hr=CoCreateInstance(&CLSID_Tracker, null, CLSCTX_ALL,  
 &IID_ITracker, &pITracker);
         if (FAILED(hr))
         {   printf("Failed to create object x%x\n",hr);
         }
         else
         {       int g, status;
                 printf("Object created, calling ITracker.ReadConfig(),  
 ITracker = %p\n", pITracker);
                 status =  
 pITracker.ReadConfig(fromString(`"C:\TD\Test\trackerconfig.txt"`));
                 if (status < 0)
                         printf("Failed! Error = %d\n", status);
                 printf("Calling ITracker.WriteConfig(), ITracker =  
 %p\n", pITracker);
                 status =  
 pITracker.ReadConfig(toBSTR(`E:\trackerconfig.txt`));
                 if (status < 0)
                         printf("Failed! Error = %d\n", status);
                 fflush(stdout);
                 pITracker.Release();
         }
         CoUninitialize();
         return EXIT_SUCCESS;
 }
 --------------
 I based this off the sample provided with DMD. I have tried to get this  
 working with Juno, DWin and the basic Phobos libraries to no avail. I am  
 certain I must be doing something really stupid, but for the life of me  
 cannot figure it out. I don't post problems often as I can usually find  
 my answers though Google, but this one has me stumped.

 If someone can please point out what I am doing wrong, I would be  
 eternally grateful.

 Steve

Put some logging or debug step-by-step to understand at what line does the access violation take place. Besides, try using `"C:\TD\Test\trackerconfig.txt"`w or toUTF16z(someFileName) instead of fromString(`"C:\TD\Test\trackerconfig.txt"`). Hope this helps.

Thanks for your tips, but no joy. It is failing right at the call to the method for the COM object. The odd part is that some methods cause an Access Violation and some methods just silently fail. I even tried some of the set/get functions and the set appears to work, but then the get function causes an Access Violation. I start thinking that something is wrong with my reference to the vtable or something. I used tlbimpd.exe from the Juno project to generate the interfaces for the OCX. Is there a better way to do this? Steve
Jul 25 2008