Compartilhar via


__clrcall

Especifica que uma função só pode ser chamada de um código gerenciado. Use __clrcall para todas as funções virtuais que serão chamadas somente do código gerenciado. No entanto, essa convenção de chamada não pode ser usada para as funções que serão chamadas a partir do código nativo. O modificador de __clrcall é específico da Microsoft.

Use __clrcall para melhorar o desempenho ao chamar de uma função gerenciada em uma função gerenciada virtual ou da função gerenciada para a função gerenciada pelo ponteiro.

Os pontos de entrada são funções separadas geradas pelo compilador. Se uma função tem pontos de entrada nativos e gerenciados, um deles será a função real com a implementação da função. Outra função será uma função separada (uma conversão) que chamará a função real e deixará Common Language Runtime executar PInvoke. Ao marcar uma função como __clrcall, você indica que a implementação da função deverá ser MSIL e que a função nativa do ponto de entrada não será gerada.

Ao colocar o endereço de uma função nativa se __clrcall não for especificado, o compilador usará o ponto de entrada nativo. __clrcall indica que a função é gerenciada e que não há necessidade de passar pela transição de gerenciada a nativa. Nesse caso, o compilador usa o ponto de entrada gerenciado.

Quando /clr (não /clr:pure ou /clr:safe) é usado e __clrcall não é usado, usar o endereço de uma função sempre retorna o endereço da função nativa do ponto de entrada. Quando __clrcall é usado, a função nativa do ponto de entrada não é criada. Assim, você obtém o endereço da função gerenciada, não uma função de conversão do ponto de entrada. Para mais informações, confira Conversão dupla. As opções do compilador /clr:pure e /clr:safe foram preteridas no Visual Studio 2015 são incompatíveis com o Visual Studio 2017.

/clr (Compilação do Common Language Runtime) implica que todas as funções e ponteiros de função são __clrcall e o compilador não permitirá que uma função dentro de compiland seja marcada como algo diferente de __clrcall. Quando /clr:pure é usado, __clrcall, só pode ser especificado em ponteiros da função e em declarações externas.

Você pode chamar diretamente as funções __clrcall de código C++ existente que foi compilado usando /clr, desde que essa função tenha uma implementação de MSIL. __clrcall funções não podem ser chamadas diretamente de funções que têm asm embutido e chamam intrínsecos específicos da CPU, por exemplo, mesmo que essas funções sejam compiladas com /clr.

Os ponteiros da função __clrcall devem ser usados somente no domínio de aplicativo no qual foram criados. Em vez de transmitir ponteiros da função __clrcall pelos domínios de aplicativo, use CrossAppDomainDelegate. Para mais informações, confira Domínios de aplicativo e Visual C++.

Exemplos

Quando uma função é declarada com __clrcall, o código é gerado quando necessário; por exemplo, quando a função é chamada.

// clrcall2.cpp
// compile with: /clr
using namespace System;
int __clrcall Func1() {
   Console::WriteLine("in Func1");
   return 0;
}

// Func1 hasn't been used at this point (code has not been generated),
// so runtime returns the adddress of a stub to the function
int (__clrcall *pf)() = &Func1;

// code calls the function, code generated at difference address
int i = pf();   // comment this line and comparison will pass

int main() {
   if (&Func1 == pf)
      Console::WriteLine("&Func1 == pf, comparison succeeds");
   else
      Console::WriteLine("&Func1 != pf, comparison fails");

   // even though comparison fails, stub and function call are correct
   pf();
   Func1();
}
in Func1
&Func1 != pf, comparison fails
in Func1
in Func1

O exemplo a seguir mostra que você pode definir um ponteiro de função de modo a declarar que o ponteiro de função será invocado apenas de códigos gerenciados. Isso permite que o compilador chame diretamente a função gerenciada e evita o ponto de entrada nativo (problema de duas conversões).

// clrcall3.cpp
// compile with: /clr
void Test() {
   System::Console::WriteLine("in Test");
}

int main() {
   void (*pTest)() = &Test;
   (*pTest)();

   void (__clrcall *pTest2)() = &Test;
   (*pTest2)();
}

Confira também

Convenções de passagem e nomenclatura de argumentos
Palavras-chave