Get varient array from VC++ dll to vb.net application - vb.net

I have to get the Features array in vb.net application. How this can be done. This is a function in VC++ .
STDMETHODIMP CclsLicense::FeatureList(VARIANT* Features,BSTR HostName, VARIANT_BOOL *ret){
USES_CONVERSION;
int status = 0;
int iCount = 0;
int nLicenseFeatures = 0;
char **featureList = NULL; // List of features
// Safe Array
SAFEARRAYBOUND bound[1];
SAFEARRAY *safeArray = NULL; // A Safe array for VB
CComVariant *pBstr = NULL; // Array of BSTR Value
// Initialize the return value
*ret = VARIANT_FALSE;
nLicenseFeatures = 0;
featureList = new char*[MAX_FEATURES];
for (i=0;i<4;i++)
{
featureList[nLicenseFeatures]=array[i];
nLicenseFeatures++;
}
// Array starts at 0 and has the number of features as elements
bound[0].lLbound = 0;
bound[0].cElements = nLicenseFeatures;
// Initialize Array
if((safeArray = ::SafeArrayCreate( VT_VARIANT, 1, bound)) == NULL)
return E_FAIL;
::VariantClear(Features);
Features->vt = VT_VARIANT | VT_ARRAY;
Features->parray = safeArray;
//use direct access to data
if(FAILED(hr = ::SafeArrayAccessData(safeArray, (void HUGEP**)&pBstr)) || pBstr == NULL)
return hr;
iCount = 0;
while( featureList[iCount] != NULL )
{
// Add to Array
if(pBstr[iCount].bstrVal != NULL)
{
::SysFreeString(pBstr[iCount].bstrVal);
pBstr[iCount].bstrVal = NULL;
}
if(featureList[iCount] == NULL)
pBstr[iCount].bstrVal = ::SysAllocString(OLESTR("")); //imposible
else
pBstr[iCount].bstrVal = ::SysAllocString(T2OLE(featureList[iCount]));
pBstr[iCount].vt = VT_BSTR;
// Increment counter
iCount++;
}
// Release Array
::SafeArrayUnaccessData(safeArray);
*ret = VARIANT_TRUE;
return S_OK;
}
Vb.Net function to get the list of features
Public Shared Function FeatureList(ByVal strLicensePath As String)
Dim features(10) As String
Try
m_objUTSLicense = CreateObject("dll name")
Call m_objUTSLicense.FeatureList(features, "192.168.1.3")
Catch ex As Exception
End Try
Dim i As Integer
Dim size As Integer = features.Length
For i = 0 To size - 1
MessageBox.Show(features(i))
Next
End Function
When i am trying this code, getting the error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt"

I can't test this without your whole project, but you might try declaring a member variable (rather than a local) so that you can apply the necessary marshalling attribute. Something like:
Imports System.Runtime.InteropServices
<MarshalAs(UnmanagedType.SafeArray, safearraysubtype:=VarEnum.VT_BSTR)>
Private features As System.Array

Related

Why doesn't my number sequence print from the 2d arraylist correctly?

I cannot get the loop to work in the buildDimArray method to store the number combinations "11+11", "11+12", "11+21", "11+22", "12+11", "12+12", "12+21", "12+22", "21+11", "21+12", "21+21", "21+22", "22+11", "22+12", "22+21", and "22+22" into the 2d arraylist with each expression going into one column of the index dimBase-1 row. The loop may work for other people, but for some reason mine isn't functioning correctly. The JVM sees the if dimBase==1 condition, but refuses to check the other conditions. The "WTF" not being printed as a result from the buildDimArray method. If dimBase=1, it prints successfully, but doesn't for the other integers. The dimBase==3 condition needs a loop eventually. The "WTF" is for illustrative purposes. I could get away with a 1d arraylist, but in the future I will likely need the 2d arraylist once the program is completed.
package jordanNumberApp;
import java.util.Scanner;
import java.util.ArrayList;
/*
* Dev Wills
* Purpose: This code contains some methods that aren't developed. This program is supposed to
* store all possible number combinations from numbers 1-dimBase for the math expression
* "##+##" into a 2d arraylist at index row dimBase-1 and the columns storing the
* individual combinations. After storing the values in the arraylist, the print method
* pours the contents in order from the arraylist as string values.
*/
public class JordanNumberSystem {
// a-d are digits, assembled as a math expression, stored in outcomeOutput, outcomeAnswer
public static int dimBase, outcomeAnswer, a, b, c, d;
public static String inputOutcome, outcomeOutput;
public static final int NUM_OF_DIMENSIONS = 9; //Eventually # combinations go up to 9
public static ArrayList<ArrayList<String>> dimBaseArray;
public static Scanner keyboard;
/*
* Constructor for JordanNumber System
* accepts no parameters
*/
public JordanNumberSystem() // Defunct constructor
{
// Declare and Initialize public variables
this.dimBase = dimBase;
this.outcomeOutput = outcomeOutput;
this.outcomeAnswer = outcomeAnswer;
}
// Set all values of variable values
public static void setAllValues()
{
// Initialize
dimBase = 1;
outcomeAnswer = 22; // variables not used for now
outcomeOutput = "1"; // variables not used for now
//a = 1;
//b = 1;
//c = 1;
//d = 1;
dimBaseArray = new ArrayList<ArrayList<String>>();
keyboard = new Scanner(System.in);
}
public static void buildDimArray(int dim)
{
dimBase = dim;
try
{
//create first row
dimBaseArray.add(dimBase-1, new ArrayList<String>());
if( dimBase == 1)
{
a = b = c = d = dimBase ;
dimBaseArray.get(0).add(a+""+b+"+"+c+""+d);
System.out.println("WTF"); // SHOWS
}
else if (dimBase == 2)
{ // dim = 2
a = b = c = d = 1 ;
System.out.println("WTF"); // doesn't show
// dimBaseArray.get(dimBase-1).add(a+""+b+"+"+c+""+d);
for( int i = 1 ; i <= dim ; i++)
a=i;
for( int j = 1 ; j <= dim ; j++)
b=j;
for( int k = 1 ; k <= dim ; k++)
c=k;
for( int l = 1 ; l <= dim ; l++)
{
d=l;
dimBaseArray.get(dim-1).add(a+""+b+"+"+c+""+d);
}
}
else if (dimBase == 3)
{
a = b = c = d = dimBase;
dimBaseArray.get(2).add(a+""+b+"+"+c+""+d);
System.out.println("WTF");
}
}catch (IndexOutOfBoundsException e)
{
System.out.println(e.getMessage());
}
}
public static void printArray(int num) // Prints the contents of the array
{ // Fixing the printing method
try
{
int i = num-1;
for( String string : dimBaseArray.get(i))
{
System.out.println(string);
System.out.println("");
}
} catch (IndexOutOfBoundsException e)
{
System.out.println(e.getMessage());
}
}
public static void main(String[] args) throws java.lang.IndexOutOfBoundsException
{
setAllValues(); // sets the initial a,b,c,d values and dimBase, initializes 2d arraylist
// Get the Dimension Base number
System.out.println("Enter Dimension Base Number. Input an integer: ");
int dimBaseInput = keyboard.nextInt(); // Receives integer
dimBase = dimBaseInput;
if( dimBase != 1 && dimBase != 2 && dimBase != 3)
{// Error checking
System.out.println("invalid Dimension Base Number should be 1 or 2 ");
System.exit(1);
}
// Build the arraylist, print, clear, exit
buildDimArray(dimBase);
printArray(dimBase);
dimBaseArray.clear();
System.exit(1);
}
}// End of class

Revit Transform Matrix from point cloud to revit link

We insert a point cloud in Revit and have to move and rotate it in several axles to get a good world alignment. We then need to apply the same transforms to a Revit MEP link that contains edgwise piping.
I have acquired the 3x4 matrix from the point cloud in revit, I would like to apply that to the revit mep link so that they are in alignment.
I have successfully applied the translation portion of the transform, I am stuck on the rotation portion. Could someone please assist with this. Dyslexia and Matrices do not work well together.
Thanks to Jeremy at the Building Coder for getting me this far!
9/4/19 - I edited the rotational part of the code, however the "ElementTransformUtils.RotateElement" does not have any effect on the link in Revit.
Autodesk.Revit.DB.View
pView = ActiveUIDocument.Document.ActiveView;Autodesk.Revit.DB.Transaction
t = new Autodesk.Revit.DB.Transaction(ActiveUIDocument.Document, "EdgewiseCoordination");
t.Start();
UIDocument uidoc = this.ActiveUIDocument;
Document document = uidoc.Document;
Autodesk.Revit.ApplicationServices.Application application = document.Application;
ElementId elementid = null;
elementid = uidoc.Selection.PickObject(ObjectType.Element, "Select element to Copy Transform or ESC to reset the view").ElementId;
Element e = document.GetElement(elementid);
Instance ei = e as Instance;
Transform pct = ei.GetTransform();
ElementId elementid2 = null;
elementid2 = uidoc.Selection.PickObject(ObjectType.Element, "Select element to Apply Transform or ESC to reset the view").ElementId;
Element e2 = document.GetElement(elementid2);
Instance ei2 = e2 as Instance;
ElementTransformUtils.MoveElement(document,elementid2,pct.Origin);
Line lineaxis = GetRotationAxisFromTransform(pct);
double tangle = GetRotationAngleFromTransform(pct);
ElementTransformUtils.RotateElement(document,elementid2,lineaxis,tangle);
t.Commit();
}
private static Line GetRotationAxisFromTransform(Transform transform)
{
double x = transform.BasisY.Z - transform.BasisZ.Y;
double y = transform.BasisZ.X - transform.BasisX.Z;
double z = transform.BasisX.Y - transform.BasisY.X;
return Line.CreateUnbound(transform.Origin, new XYZ(x, y, z));
}
private static double GetRotationAngleFromTransform(Transform transform)
{
double x = transform.BasisX.X;
double y = transform.BasisY.Y;
double z = transform.BasisZ.Z;
double trace = x + y + z;
return Math.Acos((trace - 1) / 2.0);
}
Earlier Code to save out the transform----------------------------------
public void Objectlocation()
{
Autodesk.Revit.DB.View
pView = ActiveUIDocument.Document.ActiveView;Autodesk.Revit.DB.Transaction
t = new Autodesk.Revit.DB.Transaction(ActiveUIDocument.Document, "Objectlocation");
t.Start();
UIDocument uidoc = this.ActiveUIDocument;
Document document = uidoc.Document;
Autodesk.Revit.ApplicationServices.Application application = document.Application;
ElementId elementid = null;
elementid = uidoc.Selection.PickObject(ObjectType.Element, "Select element or ESC to reset the view").ElementId;
Element e = document.GetElement(elementid);
Instance ei = e as Instance;
Transform pct = ei.GetTransform();
//string spctrans = TransformString(pct);
//TaskDialog.Show("Point Cloud Transform", spctrans);
//spctrans = (spctrans + ",0,0,0,1");
string slocx = TransformStringX(pct);
string slocy = TransformStringY(pct);
string slocz = TransformStringZ(pct);
string slocation = (slocx + "," + slocy + "," + slocz + ",0,0,0,1");
using (StreamWriter sw = new StreamWriter("test.txt"))
{
sw.WriteLine(slocation);
}
t.Commit();
}
static public string RealString( double a )
{
return a.ToString( "0.####################" );
}
static public string PointStringX( XYZ p )
{
double convunit = 0;
convunit = UnitUtils.ConvertFromInternalUnits(p.X,DisplayUnitType.DUT_DECIMAL_INCHES);
return string.Format( "{0}", RealString( convunit ));
}
static public string TransformStringX( Transform t )
{
return string.Format( "{0},{1},{2},{3}", PointStringX( t.BasisX ),
PointStringX( t.BasisY ), PointStringX( t.BasisZ ), PointStringX( t.Origin ) );
}
static public string PointStringY( XYZ p )
{
double convunit = 0;
convunit = UnitUtils.ConvertFromInternalUnits(p.Y,DisplayUnitType.DUT_DECIMAL_INCHES);
return string.Format( "{0}", RealString( convunit ));
}
static public string TransformStringY( Transform t )
{
return string.Format( "{0},{1},{2},{3}", PointStringY( t.BasisX ),
PointStringY( t.BasisY ), PointStringY( t.BasisZ ), PointStringY( t.Origin ) );
}
static public string PointStringZ( XYZ p )
{
double convunit = 0;
convunit = UnitUtils.ConvertFromInternalUnits(p.Z,DisplayUnitType.DUT_DECIMAL_INCHES);
return string.Format( "{0}", RealString( convunit ));
}
static public string TransformStringZ( Transform t )
{
return string.Format( "{0},{1},{2},{3}", PointStringZ( t.BasisX ),
PointStringZ( t.BasisY ), PointStringZ( t.BasisZ ), PointStringZ( t.Origin ) );
}
I edited the stuff you had on bcoder to split up the matrix in order to match the acad api that I was feeding it into.
ACAD API below-----------------------------------------------------------
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using System.Reflection;
namespace Transformer
{
public class Commands
{
[CommandMethod("TRANS", CommandFlags.UsePickSet)]
static public void TransformEntity()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Our selected entity (only one supported, for now)
ObjectId id;
// First query the pickfirst selection set
PromptSelectionResult psr = ed.SelectImplied();
if (psr.Status != PromptStatus.OK || psr.Value == null)
{
// If nothing selected, ask the user
PromptEntityOptions peo =
new PromptEntityOptions(
"\nSelect entity to transform: "
);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
id = per.ObjectId;
}
else
{
// If the pickfirst set has one entry, take it
SelectionSet ss = psr.Value;
if (ss.Count != 1)
{
ed.WriteMessage(
"\nThis command works on a single entity."
);
return;
}
ObjectId[] ids = ss.GetObjectIds();
id = ids[0];
}
PromptResult pr = ed.GetString("\nEnter property name: ");
if (pr.Status != PromptStatus.OK)
return;
string prop = pr.StringResult;
// Now let's ask for the matrix string
pr = ed.GetString("\nEnter matrix values: ");
if (pr.Status != PromptStatus.OK)
return;
// Split the string into its individual cells
string[] cells = pr.StringResult.Split(new char[] { ',' });
if (cells.Length != 16)
{
ed.WriteMessage("\nMust contain 16 entries.");
return;
}
try
{
// Convert the array of strings into one of doubles
double[] data = new double[cells.Length];
for (int i = 0; i < cells.Length; i++)
{
data[i] = double.Parse(cells[i]);
}
// Create a 3D matrix from our cell data
Matrix3d mat = new Matrix3d(data);
// Now we can transform the selected entity
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
Entity ent =
tr.GetObject(id, OpenMode.ForWrite)
as Entity;
if (ent != null)
{
bool transformed = false;
// If the user specified a property to modify
if (!string.IsNullOrEmpty(prop))
{
// Query the property's value
object val =
ent.GetType().InvokeMember(
prop, BindingFlags.GetProperty, null, ent, null
);
// We only know how to transform points and vectors
if (val is Point3d)
{
// Cast and transform the point result
Point3d pt = (Point3d)val,
res = pt.TransformBy(mat);
// Set it back on the selected object
ent.GetType().InvokeMember(
prop, BindingFlags.SetProperty, null,
ent, new object[] { res }
);
transformed = true;
}
else if (val is Vector3d)
{
// Cast and transform the vector result
Vector3d vec = (Vector3d)val,
res = vec.TransformBy(mat);
// Set it back on the selected object
ent.GetType().InvokeMember(
prop, BindingFlags.SetProperty, null,
ent, new object[] { res }
);
transformed = true;
}
}
// If we didn't transform a property,
// do the whole object
if (!transformed)
ent.TransformBy(mat);
}
tr.Commit();
}
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
ed.WriteMessage(
"\nCould not transform entity: {0}", ex.Message
);
}
}
}
}
END ACAD API

Passing string array from Borland C++ to C#

I want to pass list of email address strings from Borland C++ to my C# library. Below my C# side code. I could make call to PrintName() method and it works. Now I want to print email addresses, but if I call PrintEmails() function nothing happens. Could you please suggest how I can pass multiple email addresses to C# lib.
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("4A686AB1-8425-43D9-BD89-B696BB5F6A18")]
public interface ITestConnector
{
void PrintEmails(string[] emails);
void PrintName(string name);
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(ITestConnector))]
[Guid("7D818287-298A-41BF-A224-5EAC9C581BD0")]
public class TestConnector : ITestConnector
{
public void PrintEmails(string[] emails)
{
System.IO.File.WriteAllLines(#"c:\temp\emails.txt", emails);
}
public void PrintName(string name)
{
System.IO.File.WriteAllText(#"c:\temp\name.txt", name);
}
}
I have imported TLB file of above C# library into RAD Studio and my C++ side code is as below.
interface ITestConnector : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE PrintEmails(LPSAFEARRAY* emails/*[in,out]*/) = 0; // [-1]
virtual HRESULT STDMETHODCALLTYPE PrintName(WideString name/*[in]*/) = 0; // [-1]
};
TTestConnector *connector = new TTestConnector(this);
SAFEARRAYBOUND bounds[] = {{2, 0}}; //Array Contains 2 Elements starting from Index '0'
LPSAFEARRAY pSA = SafeArrayCreate(VT_VARIANT,1,bounds); //Create a one-dimensional SafeArray of variants
long lIndex[1];
VARIANT var;
lIndex[0] = 0; // index of the element being inserted in the array
var.vt = VT_BSTR; // type of the element being inserted
var.bstrVal = ::SysAllocStringLen( L"abc#xyz.com", 11 ); // the value of the element being inserted
HRESULT hr= SafeArrayPutElement(pSA, lIndex, &var); // insert the element
// repeat the insertion for one more element (at index 1)
lIndex[0] = 1;
var.vt = VT_BSTR;
var.bstrVal = ::SysAllocStringLen( L"pqr#xyz.com", 11 );
hr = SafeArrayPutElement(pSA, lIndex, &var);
connector->PrintEmails(pSA);
delete connector;
Below C++ side code worked in my case.
SAFEARRAYBOUND saBound[1];
saBound[0].cElements = nElements;
saBound[0].lLbound = 0;
SAFEARRAY *pSA = SafeArrayCreate(VT_BSTR, 1, saBound);
if (pSA == NULL)
{
return NULL;
}
for (int ix = 0; ix < nElements; ix++)
{
BSTR pData = SysAllocString(elements[ix]);
long rgIndicies[1];
rgIndicies[0] = saBound[0].lLbound + ix;
HRESULT hr = SafeArrayPutElement(pSA, rgIndicies, pData);
_tprintf(TEXT("%d"), hr);
}

I can't figure out how to call a variable from another method

I am am trying to call a variable in another method to my array.
var Com = the difficulty for the game. But the method below I'm trying to call the var Com, for: var c = Com.GetChoice();
Not sure why I can not figure out how to call it.
public object SetDiff()
{
Console.WriteLine("Enter difficulty #: (1 = Easy, 2 = Normal, 3 = Impossible)");
var diff = Console.ReadLine();
int mode;
int.TryParse(diff, out mode);
if (mode == 1)
{
Console.Clear();
var Com = new Easy();
return Com;
}
if (mode == 2)
{
Console.Clear();
var Com = new Medium();
return Com;
}
if (mode == 3)
{
Console.Clear();
var Com = new Hard();
return Com;
}
else
{
Console.WriteLine("That is not a valid input.");
return SetDiff();
}
} // Apparently you can't set variables in a switch.
public int[] FaceOff(int num)
{
int PlayerWin = 0;
int ComWin = 0;
int Tie = num + 1;
// TODO : Get rid of TIES!
for (int i = 0; i < num; i++)
{
var p = p1.GetChoice();
var c = Com.GetChoice();
You have many different options:
Pass as parameter
public int[] FaceOff(int num, int Com){...}
make a "global" variable
private int Com;
I would also recommend you to learn OOP (Object Orientated Programming) basics.

NullPointerException when object is instantiated

This is a homework, I would appreciate any kind of answer.
Im trying to figure out why i keep getting a NullPointerException when i call the equals method. I have instantiated the object if im not mistaken, but it still doesn't work.
Exception in thread "main" 8
java.lang.NullPointerException
at labbfyra.TextBuilder.equals(TextBuilder.java:69)
at labbfyra.SkapaOrd.main(SkapaOrd.java:17)
Is this the stacktrace?
public class TextBuilder {
private static class Node{
public char inChar;
public Node next;
public Node(char c, Node nästa){
inChar = c;
next = nästa;
}
}
private Node first = null;
private Node last = null;
public TextBuilder(){
first = null;
last = null;
}
public void append(String s){
int x = s.length();
for(int i=0;i<x;i++){
Node n = new Node(s.charAt(i),null);
if(first ==null){
first = n;
last = n;
}else{
last.next = n;
last = n;
}
}
}
public int ShowSize(){
int counter = 0;
Node n = first;
while(n!=null){
counter++;
n=n.next;
}
return counter;
}
public boolean equals(String s){
boolean eq = false;
int counter = 0;
char[] cArray = s.toCharArray();
char[] cArrayComp = new char[10];
Node n = first;
cArrayComp[counter] = n.inChar;
while(n!=null){
counter++;
n=n.next;
cArrayComp[counter] = n.inChar; //THIS IS LINE 69
}
if(cArrayComp==cArray){
eq = true;
}
else{
eq=false;
}
return eq;
}
}
In your while loop, you check that n is not null, but then you assign n.next to n just before accessing n. The problem is that you do not ensure that the assigned value (n.next) is not null.
At a quick glance, looks like the counter variable in your while loop is going past the 10 you set your cArrayComp size to. Perhaps the string parameter being passed is longer than 10 chars?
public boolean equals(String s){
boolean eq = false;
int counter = 0;
char[] cArray = s.toCharArray();
char[] cArrayComp = new char[10];
Node n = first;
while(n!=null){
System.out.println(counter);
cArrayComp[counter] = n.inChar;
System.out.println(cArrayComp[counter]);
System.out.println(n.inChar);
n=n.next;
counter++;
}
if(cArrayComp==cArray){
eq = true;
}
else{
eq=false;
}
return eq;
}
This is the corrected version, i found a bug in your loop. Just check my version. Works at 100%