Pergunta

Eu estou tentando chamar um método de uma DLL escrito em C, do meu aplicativo C #. Aqui está como eu tenho implementado a chamada:

-> C método de assinatura: (a partir de uma empresa de terceira parte)

Int16 SSEXPORT SS_Initialize(Uint16 ServerIds[], Uint16 ServerQty, const char PTR *Binding, const char PTR *LogPath, Uint16 LogDays, Int16 LogLevel,
Uint16 MaxThreads, Uint16 ThreadTTL, Int16 (CALLBACK *ProcessMessage)(Uint16, const char PTR *, Uint32, char PTR **, Uint32 PTR *, Int16 PTR *));

-> C tipos definição:

#ifndef _CSISERVERTYPES_
#define _CSISERVERTYPES_

#if defined(OS_NT)

#define CALLBACK __stdcall 
#define SSEXPORT __stdcall
#define PTR      

typedef char                Int8;
typedef unsigned char       Uint8;
typedef short               Int16;
typedef unsigned short      Uint16;
typedef long                Int32;
typedef unsigned long       Uint32;
typedef unsigned char       Byte;
typedef unsigned short      Word;
typedef unsigned long       Dword;
typedef short               Bool;

#endif

typedef Int16 (CALLBACK *PM_Function)
        (Uint16,const char PTR *,Uint32,char PTR **,Uint32 PTR *,Int16 PTR *);

#define SS_OK               0
#define SS_NOT_INIT         -1
#define SS_PROC_ERR         -2
#define SS_ERR_TCP_SRV      -3
#define SS_ERR_OUT_MEM      -4

#ifndef NULL
#define NULL                0
#endif

#endif

-> declaração C # DLL Método:

[DllImport("CSITCPServer.dll", SetLastError = true)]
    static extern Int16 SS_Initialize(
        UInt16[] ServerIds,
        UInt16 ServerQty,
        ref string Binding,
        ref string LogPath,
        UInt16 LogDays,
        Int16 LogLevel,
        UInt16 MaxThreads,
        UInt16 ThreadTTL,
        ProcessMessageCallback callback);

Método chamada:

public static void Call_SS_Initialize()
    {   
        Int16 ret;
        UInt16[] serverIds = new UInt16[] { 2020, 2021 };
        string binding = "";
        string logPath = "";

        try
        {
            ret = SS_Initialize(
                serverIds,
                Convert.ToUInt16(serverIds.ToList().Count),
                ref binding,
                ref logPath,
                10,
                0,
                256,
                300,
                ProcessMessage);

            Console.WriteLine("Call_SS_Initialize() -> Result of SS_Initialize:  {0}", ret.ToString());
        }
        catch (Exception ex)
        {
            Int32 err = Marshal.GetLastWin32Error();
            throw new Win32Exception(err);
            //throw;
        }
    }

E então eu obter o Win32Exception: 1008 - Foi feita uma tentativa de referenciar um token que não existe

Eu sei que o problema deve estar no CHAR à conversão corda entre códigos gerenciados (C #) não gerenciado (C) e. Se eu modificar o Encadernação ou LogPath parâmetros para tipo SByte , ele não dá nenhum erro. Mas desde que os espera método para um texto (string), eu não sei como eu posso passar o texto para o método, uma vez que espera uma variável SByte ...

Estou ciente de que eu poderia ter de usar algo como MarshalAs , mas eu tentei algumas opções e não teve qualquer sucesso.

Alguém pode me dizer o que estou fazendo de errado ??

Muito obrigado !!


Aqui está a definição de retorno de chamada:

 public delegate Int16 ProcessMessageCallback(
        UInt16 ServerId,
        [MarshalAs(UnmanagedType.LPStr)] ref string RequestMsg,
        UInt32 RequestSize,
        [MarshalAs(UnmanagedType.LPStr)] ref string ResponseMsg,
        ref UInt32 ResponseSize,
        ref Int16 AppErrCode);

A coisa é que o método C DLL está esperando um parâmetro "REF". A chamada para SS_Initialize attachs a execução do ProcessMessage função de retorno. Nesta função eu preciso ser capaz de obter os parâmetros modificados (REF) de SS_Initialize ...

O senhor poderia sugerir como você acha que o código deve ser estruturado?

Obrigado !!

Foi útil?

Solução

Você não precisa usar ref para Encadernação e LogPath; eles são const char * e não vai mudar.

Isso ResponseMessage no callback irá retornar um array de strings, (char **) não apenas uma única string. O tamanho Response provavelmente vai indicar a profundidade da matriz. Tente [MarshalAs (UnamangedType.LPArray, ArraySubType = UnmanagedType.LPStr)] string [] em vez.

Outras dicas

Para mobilizar cordas você não passar ref string, apenas string. Além disso, você deve decorar cada corda com [MarshalAs( UnmanagedType.LPStr)] para indicar que você está passando cadeia que contém caracteres ASCII e é um terminador nulo.
Edit:. Você poderia também dar a sua definição deste procedimento de retorno de chamada, como você poderia cometeram erros semelhantes

Obrigado Ravadre e R Ubben , sua ajuda combinada fez o truque !!

No final, era tudo sobre como controlar adequadamente a cláusula REF nos parâmetros e usando a tag MarshalAs. Os parâmetros que são como "const char *" na parte C realmente não precisa a tag REF. Também eu usei [MarshalAs (UnmanagedType.LPStr)] para os parâmetros de cadeia. É isso aí!

ps: Stackoverflow.com é incrível! Eu já encontrei um monte de respostas a outros problemas aqui apenas pesquisando. Este é meu primeiro post e eu estou surpreso com as respostas rápidas que eu tenho para este. Parabéns a toda a equipe de funcionários e membros! ;)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top