Click here to Skip to main content
14,430,522 members
Rate this:
Please Sign up or sign in to vote.
Hi All I am new to C# and marshalling.
My objective is:
Creating an Interface in C# and implementing it in class.
One of method will take a structure [if not a good idea then pointer to structure]
For now I an try filling the structure with primitive datatype.

Generating a dll and tlb out of it.
Now, From C++ importing the tlb and use the method.

I succeeded till accessing the C# class and access one method but the one takes structure is throwing E_INVALIDARG exception.

here is my code:
From C#

namespace ComTestCS
{
   [ComVisible(true)]
   [Guid("F9386F04-2F38-4DF5-9C9C-544DF9354AAC")]
    [InterfaceType (ComInterfaceType.InterfaceIsIDispatch)]
    public interface IShCom
    {
       int getHello(int x);       
       void getCSObj(out CSStObj ob);
    }

     [
       ComVisible(true),
       Guid("E2B721B2-5AEA-4AD7-BCC2-1DA51D0E9C79"),   
       ClassInterface(ClassInterfaceType.None),
       ComSourceInterfaces (typeof(IShCom))    ,
       ProgId("ShCom")
       
   ]

   public class ShCom : IShCom
    {
       public int getHello(int x)
       {
           System.IO.TextWriter textWriter = System.Console.Out;
           textWriter.WriteLine("getHello");//its printing
           return x+2;       
       }
      
       public void getCSObj(out CSStObj ob)//not working at all
       {
           System.IO.TextWriter textWriter = System.Console.Out;
           textWriter.WriteLine("getCSObj");
           ob = new CSStObj();
           ob.intData= 45;              
       }
    }

    [
    ComVisible(true),
    Guid("93BA11B9-A89B-4CB4-8ACE-1CDFC42FA978"),
     StructLayout(LayoutKind.Sequential,CharSet= CharSet.Ansi) 
         
    ]
     public struct CSStObj
     {
        //[MarshalAs (UnmanagedType.I4)]
         public int intData;       
     }


Now Accessing it from C++

#import "ComTestCS.tlb"      named_guids
void main()
{

   try{

       CoInitialize(NULL);
       //regasm ComTestCS.dll /tlb: c:\bin\ComTestCS.dll /codebase
       ComTestCS::IShComPtr pShCom;
       ComTestCS::CSStObj *stObj = new ComTestCS::CSStObj();
       HRESULT hr= pShCom.CreateInstance(__uuidof(ComTestCS::ShCom));
       if(hr == S_OK)
       {
       long ret;
       //returning 10 as expected along with the console msg
       ret =pShCom->getHello(8L);
       pShCom->getCSObj(stObj);    //exception here   
   }
   }
    catch(_com_error& ce)
   {

      cout<<ce.Error()<<(wchar_t*)ce.Description();//E_INVALIDARG 
   }
  
   CoUninitialize();
  
}

Please help!
Thanks in advance
Posted
Updated 27-Apr-15 23:56pm
v3
Rate this:
Please Sign up or sign in to vote.

Solution 1

If you are working with primitive data type you can use direct memory access via casting. It is better to create memory in the process/language where you used it and NOT transfer between c# and C++. If you want to use C# objects in C++ you need CLR project in C++.

Take a look at my article about an easy way to work with that issue.
   
Rate this:
Please Sign up or sign in to vote.

Solution 2

Hi All thanks for the response ,
Actually I have to use non CLR C++ native code.

I got the answer from :
Here
see the Native Exe calling Managed Dll

Just twisted little bit for my need

C# code:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace CSDll
{
    using System;

    [
    Guid("A2BDE14F-EC09-4E3C-9E39-A24B49352120")
    ]
    public struct CSStObj
    {
        //[MarshalAs (UnmanagedType.I4)]
        public int intData;
        [MarshalAs(UnmanagedType.BStr)]
        public string strData;
    }

    [Guid("D4660088-308E-49fb-AB1A-77224F3FF851")]
    public interface IMyManagedInterface
    {
        int factorial(int arg);
        void getCSObj(out CSStObj ob);
        void getCSObjs([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_USERDEFINED)] out CSStObj[] ob);
      //  void getCSObjs(out List<csstobj> ob);
    }

    /// <summary>
    ///    Summary description for Class1.
    /// </summary>
    [Guid("46A951AC-C2D9-48e0-97BE-91F3C9E7B065")]
    public class Class1 : IMyManagedInterface
    {
        public Class1()
        {
        }

        public int factorial(int arg)
        {
            int result;

            if (arg == 1)
            {
                result = arg;
            }
            else
            {
                result = arg * factorial(arg - 1);
            }

            return result;
        }
        public void getCSObj(out CSStObj ob)
        {
            System.IO.TextWriter textWriter = System.Console.Out;
            textWriter.WriteLine("getCSObj");
            ob.intData = 7;
            ob.strData = "hiCPP";
        }

        public void getCSObjs([MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_USERDEFINED)] out CSStObj[] ob)
        {
            System.IO.TextWriter textWriter = System.Console.Out;
            textWriter.WriteLine("getCSObjs");
    

            ob =
           new CSStObj[]{
                new CSStObj() { intData = 1, strData = "1" },
                new CSStObj() { intData = 2, strData = "2" },
                new CSStObj() { intData = 3, strData = "3" }
            };
            
        }

    }
}</csstobj>




In Atl non clr project

#include "stdafx.h"
#pragma once

#include "windows.h"
#include <stdio.h>
#import "C:\bin\CSDll.tlb"      named_guids 
//#import "CSDll.tlb" named_guids

int main(int argc, char* argv[])
{
   try{
    HRESULT hRes = S_OK;
    CoInitialize(NULL);
      
  
    CSDll::IMyManagedInterface *pManagedInterface = NULL;

    hRes = CoCreateInstance(CSDll::CLSID_Class1, NULL, CLSCTX_INPROC_SERVER, 
     CSDll::IID_IMyManagedInterface, reinterpret_cast<void**> (&pManagedInterface));

    if (S_OK == hRes)
    {
        long retVal =0;
        hRes = pManagedInterface->raw_factorial(4, &retVal);
        printf("The value returned by the dll is %ld\n",retVal);
		
		CSDll::CSStObj stObj;
      pManagedInterface->getCSObj(&stObj); 
	  printf("getCSObj sent is %ld %s\n",stObj.intData,stObj.strData);

     SAFEARRAY* saValues(NULL);
     pManagedInterface->getCSObjs(&saValues);
     ////////////////////////////////////////
     
      CSDll::CSStObj* pVals;
      HRESULT hr = SafeArrayAccessData(saValues, (void**)&pVals); // direct access to SA memory
      if (SUCCEEDED(hr))
      {
        long lowerBound, upperBound;  // get array bounds
        SafeArrayGetLBound(saValues, 1 , &lowerBound);
        SafeArrayGetUBound(saValues, 1, &upperBound);

        long cnt_elements = upperBound - lowerBound + 1; 
        for (int i = 0; i < cnt_elements; ++i)  // iterate through returned values
        {                              
          CSDll::CSStObj pVal = pVals[i];   
          printf("getCSObjs Array of Struct sent is %ld %s\n",pVal.intData,pVal.strData);
        }       
        SafeArrayUnaccessData(saValues);
     }

     
     
     SafeArrayDestroy(saValues);
     saValues = NULL; // set the pointer to NULL
     /////////////////////////////////////////
	  
	  
        pManagedInterface->Release();
    }


   } catch(_com_error& ce)
   {
      
      printf("Exception::%d||%s",ce.Error(),(wchar_t*)ce.Description());
   }

    CoUninitialize();
    return 0;
}


and I got access to String,Structure,Array of Structure etc all what I need in my next stage.
   
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100