O Caminho do C++ Interop

No último post eu mencionei o C++ Interop (aka IJW) como a provável tecnologia mais útil para implementar o tipo de interação entre código managed e unmanaged necessário para fazer o VART interagir com o C# e, posteriormente, com o Silverlight. Pois bem, meu palpite parece estar certo segundo o meu primeiro teste bem sucedido que consegui realizar hoje.

Criando um Wrapper Managed para código Unmanaged

Graças a esse pequeno how-to da MSDN, pude criar um wrapper para uma das classes do VART. A classe que escolhi para testar esse recurso foi a Point4D por ser uma das classes mais simples da biblioteca.

Para criar esse wrapper adicionei um novo projeto de biblioteca dinâmica C++ com suporte ao CLR em minha solução no Visual Studio. Ajustei as referências e caminhos necessários para que esse projeto pudesse incluir classes da biblioteca VART. Em um arquivo .cpp da minha solução incluí a classe original, declarei um namespace VartCLR e criei a classe de wrapper. O código ficou como segue:

#include "vart/point4d.h"
#include <vcclr.h>
#using <System.dll>

using namespace System;

namespace VartCLR
{
	public value class Point4D
	{
	public:
		Point4D(double x, double y, double z) : m_Impl( new VART::Point4D(x,y,z,1.0) ) {}
		Point4D(double x, double y, double z, double w) : m_Impl( new VART::Point4D(x,y,z,w) ) {}

	protected:
		Point4D(VART::Point4D p) : m_Impl( new VART::Point4D(p) ) {}
	public:
		// Properties
		property double X { 
			double get() {
				return m_Impl->GetX();
			}
			void set(double value){
				m_Impl->SetX(value);
			}
		}

                /* Código similar para o Y, Z e W */
		
		// Public Methods
		double DotProduct(const Point4D ^p) {
			return m_Impl->DotProduct( *(p->m_Impl) );
		}

		Point4D CrossProduct(const Point4D ^p) {
			return Point4D(m_Impl->CrossProduct( *(p->m_Impl) ));
		}

		virtual String^ ToString() override {
			String ^str;
			str = String::Format("Point4D({0}, {1}, {2}, {3})", 
				m_Impl->GetX(), 
				m_Impl->GetY(), 
				m_Impl->GetZ(), 
				m_Impl->GetW());
			return str;
		}

	private:
		VART::Point4D *m_Impl;
}

Vale notar que nem toda a classe Point4D original foi implementada nesse wrapper, até para tornar o teste mais sucinto. Também um método adicional ToString() foi implementado para facilitar testes. Assim uma classe Point4D pode ser impressa na tela com muita facilidade para que seu valor seja verificado.

Um conhecedor de C++ vai notar muitas estranhezas nesse código. A razão disso é que a linguagem utilizada aqui é o C++/CLI, um "superconjunto" de C++ que inclui extensões para escrever código managed mais facilmente. Algumas das adições mais notáveis e que podem ser vistas nesse código são o caractere ^ utilizado para indicar ponteiros managed, a palavra chave gcnew que aloca objetos managed e também as properties que funcionam de forma semelhante ao recurso de C#. Mais informações sobre as extensões podem ser encontradas nessa página da MSDN: http://msdn.microsoft.com/en-us/library/xey702bw.aspx.

Usando a Classe no C#

Para testar se o wrapper estava funcionando sem problemas, adicionei um aplicativo de Console em C# na minha solução. Adicionei uma referência ao .dll gerado pelo wrapper no meu projeto e escrevi o seguinte código:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VartCLR;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            Point4D p1 = new Point4D(1, 0, 0);
            Point4D p2 = new Point4D(0, 1, 0);

            Point4D p3 = p1.CrossProduct(p2);
            double dot = p1.DotProduct(p2);

            System.Console.WriteLine(p3);
            System.Console.WriteLine(dot);
            System.Console.ReadKey();
        }
    }
}

A boa notícia é que funcionou perfeitamente! A saída foi conforme o esperado:

Point4D(0, 0, 1, 0)
0

O método ToString implementado no wrapper permitiu que os valores fossem impressos diretamente nas funções WriteLine do programa em C#.

Próximos Passos

Após esse ponto de partida vai ser possível começar a fazer a comunicação completa entre a biblioteca VART e o C#. Infelizmente esse é um processo trabalhoso e deverá ser feito aos poucos, já que cada classe vai exigir seu próprio wrapper. Para ver resultados o mais rápido possível pretendo começar escrevendo wrappers para as classes da aplicação descrita em Primeiro programa usando V-ART.

Last edited Jul 24, 2008 at 12:02 AM by joicekafer, version 4

Comments

No comments yet.