Hi there,
I'm trying to set the spatial location for new empty documents in VB.net (with MS Visual Basic 2008 EE) and I've got problems with handling the arguments.
My application works like:
'InitializingaaApi_Initialize(0)'Logging inaaApi_Login(...)'Creating a new documentaaApi_CreateDocument(...)'here I want to add a Spatial LocationaaSpatial_SetLocation(?,?,?,?,?)'Adding environment attributesaaApi_UpdateLinkDataColumnValue(...)aaApi_UpdateEnvAttr(...)
'InitializingaaApi_Initialize(0)
'Logging inaaApi_Login(...)
'Creating a new documentaaApi_CreateDocument(...)
'here I want to add a Spatial LocationaaSpatial_SetLocation(?,?,?,?,?)
'Adding environment attributesaaApi_UpdateLinkDataColumnValue(...)aaApi_UpdateEnvAttr(...)
I didn't find any SDK examples for aaSpatial_SetLocation() and I need to provide the following arguments:
To get GUID I thought of using the following:
aaApi_SelectDocument(docID, projID)lpcguid=aaApi_GetDocumentGuidProperty(DOC_PROP_DOCGUID, idx)
Is that right and am I correct to use String type in vb.net to get the guid? My first try failed since I got nothing readable in lpcguid.
Next I should get SRS GUID with aaSpatial_ListSRS() and the WKB-geometry with something like spatialWKB_createPolygon().
Last but not least I need to know the access indicator and I want it to be public, but unfortunately I couldn't find the value of AASPATIAL_ACCESS_PUBLIC in the API documentation.
Now I'm using PW v8i SS1 but it'll be SS3 soon.
I hope someone may help me with that issue, thank you in advance,
Maik
You will need to define a structure for the GUID and pass it by reference. When the GUID is a return value you will have to use the type IntPtr and then marshel it to a GUID structure
In C# I am using the following code for defining a GUID
using System.Runtime.InteropServices;
/// <summary> /// C style GUID structure /// </summary> [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct GUID { /// unsigned int public uint Data1; /// unsigned short public ushort Data2; /// unsigned short public ushort Data3; /// unsigned char[8] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] Data4; }
I also have the following utility methods defined in the static class that I use to encapsulate the ProjectWise API functions to convert the GUID to and from a .NET System.Guid as well as a string.
/// <summary> /// Converts a C style GUID to a System.Guid /// </summary> /// <param name="value">The C style GUID</param> /// <returns>A System.Guid equivalent</returns> public static Guid FromGUID(GUID value) { return new Guid((Int32)value.Data1, (Int16)value.Data2, (Int16)value.Data3, value.Data4); } /// <summary> /// Converts a System.Guid to a C style GUID structure /// </summary> /// <param name="value">The System.Guid to convert</param> /// <returns>A C style GUID equivalent of the System.Guid</returns> public static GUID ToGUID(Guid value) { GUID result = new GUID(); byte[] bytes = value.ToByteArray(); result.Data1 = BitConverter.ToUInt32(bytes, 0); result.Data2 = BitConverter.ToUInt16(bytes, 4); result.Data3 = BitConverter.ToUInt16(bytes, 6); result.Data4 = new byte[8]; for (int i = 8; i < bytes.Length; i++) { result.Data4[i - 8] = bytes[i]; } return result; } /// <summary> /// Gets a string representation f a C style GUID structure /// </summary> /// <param name="guidStructure">The C style GUID structure</param> /// <returns>A string representation of the GUID</returns> public static string StringFromGUID(GUID guidStructure) { Guid guid = FromGUID(guidStructure); return guid.ToString("D"); }
I use the following code to marshal the pointer to a GUID structure
IntPtr ptr = PWNative.aaApi_DmsDataBufferGetGuidProperty(_hBuffer, propID, index); if (ptr != IntPtr.Zero) { return PWNative.FromGUID((GUID)Marshal.PtrToStructure(ptr, typeof(GUID))); }
Hopefully You should be able to sort out the equivalent VB code for the above C# snippets
Also do a search on the web for "Microsoft P/Invoke Interop Assistant". It is a tool that I have found very helpful in sorting out how to import and work with the ProjectWise SDK from managed code. It can generate both C# and VB code from the C declarations ( although you do have to dig through the header files to find the underlying types and amend the C declaration before it will generate the .NET code for you)
This works fine for me for getting Guids via aaApi_GetDocumentGuidProperty.
But I can't figure out how to pass a Guid as a parameter to Boolean aaApi_GUIDGetDocumentFileSize64(Guid pDocGuid, UInt64 pFileSize)
I get ERROR:50000 Failed to get object identifier by its GUID regardless.
pFileSize is defined as
[in] pFileSize Buffer to receive the file size.
I have tried variations on the following
public static extern Boolean aaApi_GUIDGetDocumentFileSize64(Guid pDocGuid, UInt64 pFileSize);
private UInt64 GUIDGetDocumentFileSize64(string pDocGuid)
{
UInt64 pFileSize = 0;
var guid = new Guid(pDocGuid);
var ret = PW_API.aaApi_GUIDGetDocumentFileSize64(guid, pFileSize);
return pFileSize;
}
Any suggestions would be appreciated.
The setup of your function params should look similar to below. Make sure to check return values of each function and call aaApi_GetLastErrorId() and aaApi_GetLastErrorMessage() to help explain any error conditions encountered.
GUID doc1Guid = {0};UINT64 fileSize = 0;aaApi_GUIDGetDocumentFileSize64(&doc1Guid, &fileSize);
HTH,
Bob
Hi Bob,
I’m still at sea here.
UINT64 fileSize = 0; // OKGUID doc1Guid = {0}; // The compiler tells me that I can’t assign an array to a GUID type.
UINT64 fileSize = 0; // OK
GUID doc1Guid = {0}; // The compiler tells me that I can’t assign an array to a GUID type.
But in any event, my function starts with a Guid string so I need to assign this value to the GUID. I attempt to do this by converting it to a system.Guid
var guid = new Guid(inputString);
and then convert that to a GUID as defined in the post above
GUID doc1Guid =ToGUID(guid);
I then pass this to the aaApi_GUIDGetDocumentFileSize64. The GUID parameters is input only, but the fileSize variable is where I look for the result, so I call it by by reference.
aaApi_GUIDGetDocumentFileSize64(doc1Guid, ref fileSize)
I don’t understand the & in your version. There doesn’t seem to be any valid use for & in C#. Do you mean the variables should be passed by reference ?
aaApi_GUIDGetDocumentFileSize64(&doc1Guid, &fileSize)
The function returns False, but the error message is only ERROR:50000 Failed to get object identifier by its GUID.
My last attempt looks like this
UInt64 fileSize = 0;
// convert string to a system.Guid
// convert system.Guid to a GUID as defined in the post above
GUID doc1Guid = ToGUID(guid);
// The GUID parameter is input only, but the fileSize variable is where I look for the result, so I call it by by reference.
var ret = PW_API.aaApi_GUIDGetDocumentFileSize64(doc1Guid, ref fileSize); return fileSize }
The DllImport is
public static extern Boolean aaApi_GUIDGetDocumentFileSize64( GUID pDocGuid, ref UInt64 pFileSize);
regards
René
Oops. I see that &VAR means addressof-expression VAR. But can only be used in unsafe context.
Rene,
It is highly recommended to design, create, and maintain any Bentley specific code you develop to run natively within the host (in-process) product. e.g. ProjectWise Explorer (having a custom .dll), MicroStation (having a Native code MDL or Managed code MDL Addin), etc. By creating, testing, and maintaining your code completely within process you can natively debug any problem with ease and prevent a slew of problem debugging and coding across different programming languages and underlying Microsoft Visual C runtime environments. Once you create your custom code in-process and confirm proper operation then you can create public "exports" (or wrapper functions) that can be cleanly and simply called from your external (out-of-process) application with ease and reliability.
This approach decouples your (mostly) Bentley specific code running in-process from the (mostly) Microsoft specific code for your external application/interface keeping code to a clean and maintainable minimum that any developer could extend or maintain. If you choose not to follow this design approach then you are likely to encounter numerous problems including but not limited to:
I hope you consider creating your custom code in-process since the API is ready to go, supportable, and easily debuggable with useful error messages that relate to the problem and not the calling convention that can save a lot of time - when things do go wrong.
HTH,Bob