1

I have been trying to replicate the following C++ function in my C# application but I am getting an AccessViolationException at the time the method "ObjSearchObject2" is invoked. Pretty sure I am doing a lot of things wrong. The C++ function and the corresponding headers looks like this,

bool DocumentSearch(char *pFileId) { const int NUM_CONDITIONS = 1; const int NUM_TYPE_DEFNS = 1; ObjSearchObjectParm rSearchObject; ObjSearchCondition rSearchCondition; ObjObjectResults rSearchResults; char *pTypeDefnIdArray[NUM_TYPE_DEFNS]; bool bReturnValue = false; memset(&rSearchObject, 0, sizeof(ObjSearchObjectParm)); memset(&rSearchCondition, 0, sizeof(ObjSearchCondition)); memset(&rSearchResults, 0, sizeof(ObjObjectResults)); pTypeDefnIdArray[0] = "dotdA9";//Documents rSearchObject.obj_defn_ids = pTypeDefnIdArray; rSearchObject.obj_defn_count = NUM_TYPE_DEFNS; rSearchObject.num_conditions = NUM_CONDITIONS; rSearchObject.max_results = 5000; rSearchObject.search_cond = &rSearchCondition; rSearchCondition.field = "ancestor"; rSearchCondition.op = "is"; rSearchCondition.value = pFileId; if (ObjSearchObject2(&rSearchObject, &rSearchResults)) { printf("ERROR: ObjSearchObject2 returned: %s \n", ObjGetErrorMsg()); } else { printf("INFO : Number of returned results = %d \n", rSearchResults.num_results); if (rSearchResults.num_results > 0) { for (int iIndex = 0; iIndex < rSearchResults.num_results; iIndex++) { if (rSearchResults.object_handle[iIndex]) { printf("INFO : Object Id returned: %s (name=%s, updated=%s, type=%s, state=%s) \n", ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "id_object"), ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "name"), ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "date_update"), ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "id_type_definition"), ObjGetObjectAttr(rSearchResults.object_handle[iIndex], "num_state") ); ObjFreeObjectHdl(rSearchResults.object_handle[iIndex]); } } bReturnValue = true; } } return bReturnValue; } int ObjSearchObject2(ObjSearchObjectParm *, ObjObjectResults *); char * ObjGetObjectAttr(ObjApiObjectHdl objectHdl, char *attr_name); char * ObjGetErrorMsg(); void ObjFreeObjectHdl(ObjApiObjectHdl objectHdl); typedef struct _ObjSearchObjectParm { int obj_defn_count; // mandatory char **obj_defn_ids; // mandatory char *text_server_alias; // optional. char *query_string; // optional text search string ObjApiBoolean include_deleted; // defaults to OBJAPI_FALSE int max_results; // default = 200 int num_conditions; // mandatory ObjSearchCondition *search_cond; // mandatory ObjApiBoolean include_content; // mandatory for COMPLEX searches, translated to Y/N in API ObjApiBoolean include_metadata; // mandatory for COMPLEX searches, translated to Y/N in API } ObjSearchObjectParm; enum ObjApiSearchOp { OBJAPI_MATCH_ALL=1, OBJAPI_MATCH_ANY=2 }; enum ObjApiBoolean { OBJAPI_FALSE, OBJAPI_TRUE }; typedef struct _ObjSearchCondition { ObjApiSearchOp boolop; // only for complex searches char *join_relation; // only for complex searches int num_opening_brackets; // only for complex searches int num_closing_brackets; // only for complex searches char *field; char *op; char *value; } ObjSearchCondition; typedef void* ObjApiObjectHdl; typedef struct _ObjObjectResults { ObjApiObjectHdl *object_handle; int num_results; } ObjObjectResults; 

My take on this is as follows, (UPDATE: Code updated)

public class ObjectiveNativeAPI { private const string dllPath = @"objapi.dll"; public enum ObjApiBoolean { OBJAPI_FALSE, OBJAPI_TRUE }; public enum ObjApiSearchOp { OBJAPI_MATCH_ALL = 1, OBJAPI_MATCH_ANY = 2 }; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct ObjSearchObjectParm { public int obj_defn_count; public string[] obj_defn_ids; public string text_server_alias; public string query_string; public ObjApiBoolean include_deleted; public int max_results; public int num_conditions; public IntPtr search_cond; public ObjApiBoolean include_content; public ObjApiBoolean include_metadata; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct ObjSearchCondition { public ObjApiSearchOp boolop; public string join_relation; public int num_opening_brackets; public int num_closing_brackets; public string field; public string op; public string value; } [StructLayout(LayoutKind.Sequential)] public struct ObjObjectResults { public IntPtr object_handle; public int num_results; } [DllImport(dllPath, EntryPoint = "ObjSearchObject2")] public static extern int ObjSearchObject2(ref ObjSearchObjectParm objSearchObjectParm, ref ObjObjectResults objObjectResults); [DllImport(dllPath, EntryPoint = "ObjGetObjectAttr")] public static extern string ObjGetObjectAttr(IntPtr object_handle, string attr_name); [DllImport(dllPath, EntryPoint = "ObjFreeObjectHdl")] public static extern void ObjFreeObjectHdl(IntPtr object_handle); } public void Run() { ObjectiveNativeAPI.ObjSearchObjectParm rSearchObject = new ObjectiveNativeAPI.ObjSearchObjectParm(); ObjectiveNativeAPI.ObjSearchCondition rSearchCondition = new ObjectiveNativeAPI.ObjSearchCondition(); ObjectiveNativeAPI.ObjObjectResults rSearchResults = new ObjectiveNativeAPI.ObjObjectResults(); rSearchCondition.field = "ancestor"; rSearchCondition.op = "is"; rSearchCondition.value = txtCotainerId.Text; rSearchObject.obj_defn_ids = new[] {"dotdA9"}; rSearchObject.obj_defn_count = 1; rSearchObject.num_conditions = 1; rSearchObject.max_results = 5000; IntPtr search_cond = Marshal.AllocCoTaskMem(Marshal.SizeOf(rSearchCondition)); Marshal.StructureToPtr(rSearchCondition, search_cond, false); rSearchObject.search_cond = search_cond; int result = ObjectiveNativeAPI.ObjSearchObject2(ref rSearchObject, ref rSearchResults); MessageBox.Show(string.Format("FunctionResult: {0}", result)); Marshal.FreeCoTaskMem(search_cond); } 

I am a bit lost on this. I have managed to translate some other segments of this project but this is causing me grief. Any help around this would be appreciated.

8
  • You have all struct declarations wrong. You need to qualify the string members with [MarshalAs(UnmanagedType.LPStr)], the string arrays with [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)], and you need to declare pointers to substructs as IntPtr because UnmanagedType.LPStruct will not do it - or as arrays, see stackoverflow.com/q/9735294/11683. Commented Sep 7, 2017 at 6:57
  • @GSerg Not so for the the first two points. The default marshaling is fine. Commented Sep 7, 2017 at 7:39
  • @DavidHeffernan I believe the default marshaling is LPTStr (as opposed to LPStr). However I agree it's better to put CharSet=CharSet.Ansi in the [StructLayout] and then not use MarshalAs on strings. Commented Sep 7, 2017 at 8:02
  • @GSerg CharSet=CharSet.Ansi is the default isn't it. I would be explicit though. The main problems are the sub structs. Also the array in _ObjObjectResults needs attention. Commented Sep 7, 2017 at 8:03
  • @DavidHeffernan You are most likely right, but while I know LayoutKind.Sequential is the (language-dependent) default, I can't find anything on the CharSet default. Commented Sep 7, 2017 at 8:16

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.