Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to correctly P/Invoke this function?

Tags:

c#

pinvoke

How to correctly P/Invoke this function?

const char * GetReplyTo(const char * pszInText, char * pszOutText, int len)

I've tried to do it this way and got access violation exception:

[DllImport("SmartBot.dll", EntryPoint = "GetReplyTo")]
public static extern IntPtr GetReplyTo([In] [MarshalAs(UnmanagedType.LPStr)] string pszInText, IntPtr pszOutText, int len);

// somewhere below:
IntPtr pbuf = GCHandle.Alloc(new byte[1000], GCHandleType.Pinned).AddrOfPinnedObject();
GetReplyTo("hi", pbuf, 2);

UPDATE Here is pascal header for this file:

 {***************************************************************************
 * SmartBot Engine - Boltun source code,
 * SmartBot Engine Dynamic Link Library
 *
 * Copyright (c) 2003 ProVirus,
 * Created Alexander Kiselev Voronezh, Russia
 ***************************************************************************
 SmartBot.pas : Header Pascal for SmartBot Engine.
 }

unit SmartBot;

interface

{
function GetReplyTo(const InText: PChar; OutText: PChar; Len: integer): PChar;stdcall;export;
function LoadMind(MindFile: PChar): integer;stdcall;export;
function SaveMind(MindFile: PChar): integer;stdcall;export;
}
function GetReplyTo(const InText: PChar; OutText: PChar; Len: integer): PChar;stdcall;external 'smartbot.dll' name 'GetReplyTo';
function LoadMind(MindFile: PChar): integer;stdcall;external 'smartbot.dll' name 'LoadMind';
function SaveMind(MindFile: PChar): integer;stdcall;external 'smartbot.dll' name 'SaveMind';

implementation
end.

UPDATE 2 It works. Looks like I messed up with initialization function. It returns 1 on success and 0 on fail. Weird.

like image 482
Poma Avatar asked Feb 23 '23 20:02

Poma


2 Answers

You probably don't want an IntPtr here. You're making way too much work for yourself. For an output string parameter, you should use StringBuilder. You'll probably need to specify CharSet on your P/Invoke declaration, since the function appears to use one byte per character.

[DllImport("SmartBot.dll", CharSet = CharSet.Ansi)]
public static extern string GetReplyTo(string pszInText,
    StringBuilder pszOutText, int len);

var stringBuilder = new StringBuilder(1000);
GetReplyTo("hi", stringBuilder, stringBuilder.Capacity);

Also make sure you're specifying the right calling convention (the CallingConvention property on the DllImport attribute).

like image 164
Joe White Avatar answered Mar 07 '23 20:03

Joe White


you should use a StringBuilder for the second parameter that you initialize to size len

like image 25
Richard Blewett Avatar answered Mar 07 '23 20:03

Richard Blewett