How to use Halcon HOperatorSet.SetDrawingObjectCallback - c#

I had a hard time finding how to use HOperatorSet.SetDrawingObjectCallback(HTuple drawID, HTuple drawObjectEvent, HTuple callbackFunction) (Docu) in C#, specifically the part of the callback HTuple callbackFunction. Apart from a Chinese website (Link), I could not locate any examples on how to properly do this. The website itself was also not straight forward to find and the code used there throws a fatal exception. In order for other people to have a better resource on how to use the HOperatorSet.SetDrawingObjectCallback method, I decided to create this question and answer it myself.

The key here is that the HTuple callbackFunction is a function pointer that points to a delegate of the type HDrawingObject.HDrawingObjectCallback. This delegate then links to you proper callback method. The callback method includes an intptr to the drawingId and the windowId as well as a string type.
Here is the code snippet, that hopefully will make your day better:
public class SomeClass
{
public SomeClass()
{
DrawingObjectCallback = DrawingObjectCallbackHandler;
}
public void AddDrawingObject()
{
HOperatorSet.CreateDrawingObjectCircle(50, 50, 100, out var drawId);
//Get the pointer to HDrawingObjectCallback which links to our handler
var ptr = Marshal.GetFunctionPointerForDelegate(DrawingObjectCallback);
//Select the events you want to listen to
var listenTo = new HTuple("on_resize", "on_drag");
//Finally call the method
HOperatorSet.SetDrawingObjectCallback(drawId, listenTo, ptr);
HOperatorSet.AttachDrawingObjectToWindow(HalconWindow.HalconID, drawId);
}
public HDrawingObject.HDrawingObjectCallback DrawingObjectCallback { get; }
public void DrawingObjectCallbackHandler(IntPtr drawId, IntPtr windowHandle, string type)
{
int id = new HTuple(drawId);
int windowId = new HTuple(windowHandle);
//Now you have the two Ids as integers and can work from here!
}
}

Related

Efficiency of static constant list initialization in C# vs C++ static arrays

I apologize in advance. My domain is mostly C (and C++). I'm trying to write something similar in C#. Let me explain with code.
In C++, I can use large static arrays that are processed during compile-time and stored in a read-only section of the PE file. For instance:
typedef struct _MY_ASSOC{
const char* name;
unsigned int value;
}MY_ASSOC, *LPMY_ASSOC;
bool GetValueForName(const char* pName, unsigned int* pnOutValue = nullptr)
{
bool bResult = false;
unsigned int nValue = 0;
static const MY_ASSOC all_assoc[] = {
{"name1", 123},
{"name2", 213},
{"name3", 1433},
//... more to follow
{"nameN", 12837},
};
for(size_t i = 0; i < _countof(all_assoc); i++)
{
if(strcmp(all_assoc[i].name, pName) == 0)
{
nValue = all_assoc[i].value;
bResult = true;
break;
}
}
if(pnOutValue)
*pnOutValue = nValue;
return bResult;
}
In the example above, the initialization of static const MY_ASSOC all_assoc is never called at run-time. It is entirely processed during the compile-time.
Now if I write something similar in C#:
public struct NameValue
{
public string name;
public uint value;
}
private static readonly NameValue[] g_arrNV_Assoc = new NameValue[] {
new NameValue() { name = "name1", value = 123 },
new NameValue() { name = "name2", value = 213 },
new NameValue() { name = "name3", value = 1433 },
// ... more to follow
new NameValue() { name = "nameN", value = 12837 },
};
public static bool GetValueForName(string name, out uint nOutValue)
{
foreach (NameValue nv in g_arrNV_Assoc)
{
if (name == nv.name)
{
nOutValue = nv.value;
return true;
}
}
nOutValue = 0;
return false;
}
The line private static readonly NameValue[] g_arrNV_Assoc has to be called once during the host class initialization, and it is done for every single element in that array!
So my question -- can I somehow optimize it so that the data stored in g_arrNV_Assoc array is stored in the PE section and not initialized at run-time?
PS. I hope I'm clear for the .NET folks with my terminology.
Indeed the terminology is sufficient enough, large static array is fine.
There is nothing you can really do to make it more efficient out of the box.
It will load initially once (at different times depending on which version of .net and if you have a static constructor). However, it will load before you call it.
Even if you created it empty with just the predetermined size, the CLR is still going to initialize each element to default, then you would have to buffer copy over your data somehow which in turn will have to be loaded from file.
The question are though
How much overhead does loading the default static array of struct actually have compared to what you are doing in C
Does it matter when in the lifecycle of the application when its loaded
And if this is way too much over-head (which i have already assumed you have determined), what other options are possibly available outside the box?
You could possibly pre-allocate a chunk of unmanaged memory, then read and copy the bytes in from somewhere, then inturn access using pointers.
You could also create this in a standard Dll, Pinvoke just like an other un-managed DLL. However i'm not really sure you will get much of a free-lunch here anyway, as there is overhead to marshal these sorts of calls to load your dll.
If your question is only academic, these are really your only options. However if this is actually a performance problem you have, you will need to try and benchmark this for micro-optimization and try to figure out what is suitable to you.
Anyway, i don't profess to know everything, maybe someone else has a better idea or more information. Good luck

GeckoFX file download

I have some issues with GeckoFX file download.
I tried the LauncherDialog method described in a few locations such as How to handle downloading in GeckoFX 29, and a WebRequest / Webclient method.
Both method work, but they do two requests to the server. The first one will trigger the LauncherDialog.Download event, and the LauncherDialog will make a new request to get the actual file.
I use GeckoFX in a custom web client for a customer, and in this particular case, this download request requires several seconds of processing on server side and modifies the data state. The second request is delayed and the returned data isn't the same as for the first request.
Also, this particular application doesn't need a download progress window of any sorts.
Is there any way to get the data stream from the initial request? Modifying GeckoFx-Winforms is not a problem. I would prefer avoiding any modification to GeckoFX-Core, but I'll do it if required.
Well, I revisited my wrong assumptions about XPCOM programming, took a look at selected locations in Firefox/Gecko source code and found one solution. Which could be very obvious for someone with some XPCOM/XUL programming experience, but was not initially for me. So I guess sharing my solution could help a few people.
In my case, the LauncherDialog method is definitely not the way to go.
Instead, I implemented the nsIFactory, nsIExternalHelperAppService and nsIStreamListener interfaces.
nsiStreamListener
internal class MyStreamListener : nsIStreamListener
{
public MyStreamListener(/*...*/) { }
public void OnStartRequest(nsIRequest aRequest, nsISupports aContext)
{
// This will get called once, when the download "begins".
// You can initialize your things here.
}
public void OnStopRequest(nsIRequest aRequest, nsISupports aContext, int aStatusCode)
{
// This will also get called once, when the download is
// complete or interrupted. You can perform the post-download
// actions here.
if (aStatusCode != GeckoError.NS_OK) {
// download interrupted
}
else {
// download completed
}
}
public void OnDataAvailable(nsIRequest aRequest, nsISupports aContext, nsIInputStream aInputStream, ulong aOffset, uint aCount)
{
// This gets called several times with small chunks of data.
// Do what you need with the stream. In my case, I read it
// in a small buffer, which then gets written to an output
// filestream (not shown).
// The aOffset parameter is the sum of all previously received data.
var lInput = InputStream.Create(aInputStream);
byte[] lBuffer = new byte[aCount];
lInput.Read(lBuffer, 0, (int)aCount);
}
}
nsIExternalHelperAppService
public class MyExternalHelperAppService : nsIExternalHelperAppService
{
public MyExternalHelperAppService(/* ... */)
{
/* ... */
}
public nsIStreamListener DoContent(nsACStringBase aMimeContentType, nsIRequest aRequest, nsIInterfaceRequestor aWindowContext, bool aForceSave)
{
var request = Request.CreateRequest(aRequest);
var lChannel = request as HttpChannel;
try {
if (lChannel != null) {
var uri = lChannel.OriginalUri;
var contentType = lChannel.ContentType;
var contentLength = lChannel.ContentLength;
var dispositionFilename = lChannel.ContentDispositionFilename;
// Do your contenttype validation, keeping only what you need.
// Make sure you clean dispositionFilename before using it.
// If you don't want to do anything with that file, you can return null;
return new MyStreamListener(/* ... */);
}
}
catch (COMException) {
/* ... */
}
return null;
}
}
nsIFactory (you can also overload GenericOneClassNsFactory<TFactory,TType>):
public IntPtr CreateInstance(nsISupports aOuter, ref Guid iid)
{
// This is called when the content dispatcher gets a DISPOSITION_ATTACHMENT
// on the channel, or when it doesn't have any builtin handler
// for the content type. It needs an external helper to handle
// the content, so it creates one and calls DoContent on it.
MyExternalHelperAppService _myExternalHelperAppService = new MyExternalHelperAppService(...);
IntPtr result;
IntPtr iUnknownForObject = Marshal.GetIUnknownForObject(_myExternalHelperAppService);
Marshal.QueryInterface(iUnknownForObject, ref iid, out result);
Marshal.Release(iUnknownForObject);
return result;
}
public void LockFactory(bool #lock) {
// do nothing here, it's not used, only kept for backwards compatibility.
}
Then, somewhere in my initialization code, I registered my nsIFactory with the proper contract:
Xpcom.RegisterFactory(typeof(MyExternalHelperAppService).GUID,
"MyExternalHelperAppService",
"#mozilla.org/uriloader/external-helper-app-service;1",
new MyNsFactory());
And that's all.

it is possible to get stacktrace of methods calls inside call method?

I want to add more info to the logger at the call method level, and i need to know if exist possibility to get StackTrace of methods calls inside call method.
UPDATE: The purpose of this is to draw the flow of all methods called until the certain step inside call method.
EXAMPLE:
public class Type1
{
internal string method2_T1() {
return new Type2().method1_T2();
}
}
public class Type2
{
public string method1_T2()
{
return "Type2.method1_T2";
}
}
static void Main(string[] args)
{
string t = new Type1().method2_T1();
LogNow();
....
}
and the result to obtain, when I call LogNow(), are:
StackTrace of method2_T1()
...
Thanks
It's pretty easy:
var stackTrace = new StackTrace(true);
var traceToLog = stackTrace.ToString();
The true argument says to include the file info.
Todd Sprang's answer is good as the actual answer, but be aware that the stack trace will change in unpredictable ways when you move to a RELEASE build, or use async/await. Don't rely programatically on the answers because you may come unstuck when you put the code into production.
If you want to know the direct caller of a particular function, in a way Microsoft recommend, there's the useful trick using the [CallerMemberName], [CallerFilePath], and [CallerLineNumber] attributes. Mark up optional parameters like so;
public void LogWithCallerInfo(
string message,
[CallerMemberName] string memberName = "Caller",
[CallerFilePath] string sourceFilePath = "File",
[CallerLineNumber] int sourceLineNumber = 0)
{
WriteProgressMessage(..., memberName, sourceFilePath, sourceLineNumber);
}
and call like this;
LogWithCallerInfo("my message");
The three optional parameters will be replaced with the appropriate call info.

Struct contains a function and object to be handled by the function in C# .Net

I am trying to create a struct that contains a function and an object to be handled by that function. For example:
public delegate void MyFunc(object o);
public struct MyData
{
public object o;
public MyFunc func;
public MyData(object o, MyFunc func)
{
this.o = o;
this.func = func;
}
public HandleData()
{
func(o);
}
}
The purpose of this struct is to use any function to handle any data.
I wrap this struct into a IntPtr data type and send to another to handle this struct
private void PrepareData(object o, MyFunc func)
{
MyData md = new MyData(o, func);
int size = Marshal.SizeOf(md);
IntPtr wParam = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(md, wParam, false);
DoJob(wParam);
}
private void DoJob(IntPtr wParam)
{
if (wParam != IntPtr.Zero)
{
Type type = typeof(MyData);
MyData md = (MyData)Marshal.PtrToStructure(p,type);
md.HandleData();
}
}
Sometimes, I receive error like:
1) "[System.RuntimeType] = {Name = Cannot evaluate expression because the code of the current method is optimized. FullName = Cannot evaluate expression because the code of the current method is optimized.}"
2) in HanldeData function, the func instance variable has been Garbage Collected, and is not able to work properly.
like:
{Method = Cannot evaluate expression because a thread is stopped at a point where garbage collection is impossible, possibly because the code is optimized.}
Managed Debugging Assistant 'CallbackOnCollectedDelegate' has detected a problem
Note: I haven't check the "optimise code" in the property of the project.
Without a complete code example and a clear description of what you are actually trying to achieve here, it's impossible to know for sure what the best answer. That said, frankly, the whole scheme seems nuts to me. IntPtr? Seriously?
I don't see anything in your question that describes a problem that can't be accomplished more easily simply by wrapping the delegate and object in a new delegate object.
E.g.:
private void PrepareData(object o, MyFunc func)
{
DoJob(() => func(o));
}
private void DoJob(Action wParam)
{
if (wParam != null)
{
wParam();
}
}
Note that in your original code, if the only references left to your object and delegate are in the unmanaged block you allocate, they may in fact be GC'ed, as they would then be unreachable via any managed reference (which is the only thing the GC cares about).
Note also that even if the objects are still reachable via a managed reference, that the GC may move the objects in memory (e.g. to compact the heap), rendering the values you've copied into your unmanaged block of memory useless.
If you stick to the use of managed code and objects in your program, you will avoid these problems.
(I also note that your code example doesn't even seem valid, as your DoJob() parameter name is wParam, but the variable you check and marshal back to a managed struct is named p).
I am not sure that the Unmanaged Code will be GC'ed. However, I follow the tutorial: link
and what I am missing in my code is just to forget free the allocated memory for the next use.
private void DoJob(IntPtr wParam)
{
if (wParam != IntPtr.Zero)
{
Type type = typeof(MyData);
MyData md = (MyData)Marshal.PtrToStructure(p,type);
md.HandleData();
// Free the unmanaged representation of MyData struct.
Marshal.FreeHGlobal(wParam);
}
}
It works very well until now after many tests.

C to C# callback raises exception after a while

I have a tricky bug I can't find. I'm doing late-binding on from C# to a native DLL I wrote.
The late-binding seem to work fine. The problems started after I added the callbacks.
The callbacks are defined as so (in c)(On a global scale in the DLL):
typedef void (*FinishedDelegate) (ProcessResult a_bResult);
typedef void (*DownloadStatusUpdateDelegate) (int a_iParametersDownloaded, int a_iTotalParameters);
typedef void (*DownloadFinishedDelegate) (char* a_sConfiguration_values, ProcessResult a_bResult);
DownloadStatusUpdateDelegate pfDownloadStatusUpdateDelegate = NULL;
DownloadFinishedDelegate pfDownloadFinishedDelegate = NULL;
This function is exported:
PLUGIN_API BOOL DownloadConfigration(DownloadStatusUpdateDelegate a_pfStatusDelegate, DownloadFinishedDelegate a_pfFinishedDelegate);
And this is the native function implementation:
DWORD WINAPI DownloadThreadFunc(void* a_pParam)
{
while (g_iParameterDownloaded < PARAMETER_COUNT)
{
if (IsEventSignaled(g_hAbortEvent))
{
CallDownloadFinished(PROCESS_ABORT);
return 0;
}
Sleep(STATUS_DELAY);
CallDownloadStatusUpdate();
g_iParameterDownloaded += STATUS_PARAMS_JUMP;
}
CallDownloadFinished(PROCESS_SUCCESS);
return 0;
}
PLUGIN_API BOOL DownloadConfigration(DownloadStatusUpdateDelegate a_pfStatusDelegate, DownloadFinishedDelegate a_pfFinishedDelegate)
{
if (IsEventSignaled(g_hInProcessEvent))
return false;
pfDownloadStatusUpdateDelegate = a_pfStatusDelegate;
pfDownloadFinishedDelegate = a_pfFinishedDelegate;
g_iParameterDownloaded = 0;
DWORD l_dwResult = WaitForSingleObject(g_hThreadsStructGuardian, INFINITE);
if (l_dwResult == WAIT_OBJECT_0)
{
g_ahThreads[PLUGIN_THREAD_DOWNLOAD] = CreateThread(NULL, 0, DownloadThreadFunc, 0, 0, NULL);
ReleaseMutex(g_hThreadsStructGuardian);
return true;
}
return false;
}
On the managed side, the function is called here:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DownloadStatusUpdateDelegate(int a_iParametersDownloaded, int a_iTotalParameters);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void DownloadFinishedDelegate_Native(StringBuilder a_sConfigurationValues, EPluginProcessResult a_eResult);
private void OnDownloadStatusUpdate(int a_iParametersDownloaded, int a_iTotalParameters)
{
if (DownloadStatusUpdate != null)
{
DownloadStatusUpdate(a_iParametersDownloaded, a_iTotalParameters);
}
}
private void OnDownloadFinished(StringBuilder a_sConfigurationValues, EPluginProcessResult a_eResult)
{
if (DownloadFinished != null)
{
DownloadFinished(a_sConfigurationValues.ToString(), a_eResult);
}
}
public bool DownloadConfiguration()
{
bool l_bResult = DLLDownloadConfigration(OnDownloadStatusUpdate, OnDownloadFinished);
return l_bResult;
}
The weird thing is - It works for a while. I get a "Privileged Instruction" exception after some time, but as I lower STATUS_DELAY, it happens less. The exception shows up at the IsEventSignaled function - But there's simply nothing there.
The download thread syncs to the c# GUI thread to update the GUI.
I've been on this problem for way too much time. It looks like a classic calling conventions problem, but I verified it thoroughly!
Any ideas?
bool l_bResult = DLLDownloadConfigration(OnDownloadStatusUpdate, OnDownloadFinished);
The code isn't very clear, but this is the likely trouble spot. This creates two delegate objects, the callback bombs after the garbage collector runs and deletes the objects. It cannot track managed object references into unmanaged code. You'll need to create the delegates explicitly and store them in a class member so the garbage collector always sees at least one reference.
Have you tried using a lambda? As in:
bool l_bResult = DLLDownloadConfigration((downloaded, totalParams) => OnDownloadStatusUpdate(downloaded, totalParams), (values, result) => OnDownloadFinished(values, result));
My theory on this is that it is failing because your OnDownloadStatusUpdate and OnDownloadFinished methods aren't static. The underlying IL expects the 'this' object as the first invisible arg, but the C-method is not passing it when calling the callback.
EDIT: I think the answerer above me is correct, but can anyone shed some light on how the marshaller actually handles this?

Categories