Jump to content
roger911

DLL help

Recommended Posts

roger911

Hey, I'm trying to write a simple DLL utilizing OpenCV for image template matching functionality.

Here's the DLL code :

Header :

#ifndef _DLL_TUTORIAL_H_
#define _DLL_TUTORIAL_H_  // This is basically to tell compiler that we want to include this code only once(incase duplication occurs), you include it in .cpp file(which we will soon do)
#include <iostream>       // Inlcude basic c++ standard library output header(this is used for output text on the screen in our code)

#if defined DLL_EXPORT
#define DECLDIR __declspec(dllexport)
#else
#define DECLDIR __declspec(dllimport)
#endif

// We #define __declspec(dllexport) as DECLDIR macro so when compiler sees DECLDIR it will just take it as __declspec(dllexport)(say that DECLDIR is for readability)
// Note that there is also __declspec(dllimport) for internal linking with others programs but since we just need to export our functions so we can use them with Autoit, thats all we need!


extern "C"  // this extern just wraps things up to make sure things work with C and not only C++
{

	// Here we declare our functions(as we do with normal functions in c header files, our cpp file will define them(later). Remember that DECLDIR is just a shortcut for __declspec(dllexport)

	DECLDIR int MatchingMethod(int iMatchMethod, void*, std::string SearchIn, std::string SearchFor);
	DECLDIR int add(int x, int y);
}

#endif // closing #ifndef _DLL_TUTORIAL_H_

Sources :

// ITM.cpp : Defines the exported functions for the DLL application.
//

#include <Windows.h>
#include "ITM.h"
#include "stdafx.h"
#include <iostream>
#include <opencv2/opencv.hpp>

#define DLL_EXPORT

using namespace std;
using namespace cv;


extern "C"
{
    int MatchingMethod(int iMatchMethod, void*, string SearchIn, string SearchFor)
    {
        return 999;
        cv::Mat ref = cv::imread(SearchIn);
        cv::Mat tpl = cv::imread(SearchFor);

        if (ref.empty() || tpl.empty())
            return -10;

        cv::Mat gref, gtpl;
        cv::cvtColor(ref, gref, CV_BGR2GRAY);
        cv::cvtColor(tpl, gtpl, CV_BGR2GRAY);

        cv::Mat res(ref.rows - tpl.rows + 1, ref.cols - tpl.cols + 1, CV_32FC1);
        cv::matchTemplate(gref, gtpl, res, iMatchMethod);
        cv::threshold(res, res, 0.1, 1., CV_THRESH_TOZERO);

        while (true)
        {
            double minval, maxval, threshold = 0.6;
            cv::Point minloc, maxloc;
            cv::minMaxLoc(res, &minval, &maxval, &minloc, &maxloc);

            if (maxval >= threshold)
            {
                return 1;
                break;
            }
            else
            {
                return 0;
                break;
            }
        }

        ref.release();
        tpl.release();
        res.release();
        return -20;
    }

    int add(int x, int y)
    {
        return x + y;
    }

}
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}
LIBRARY ITM

DESCRIPTION "Image Template Matching DLL"
EXPORTS
    MatchingMethod @1
    add @2

Calling it in the autoit code :

...

$fooResult1 = 1
$fooResult1 = DllCall("../Dependancies/ITM.dll", "int:cdecl", "MatchingMethod", "int", 1, "void*", Null, "std::string", "../img/Test/pngsearch.png", "std::string", "../img/Test/lookfor1.bmp")
;$fooResult1 = DllCall("../Dependancies/ITM.dll", "int:cdecl", "add", "int", 2, "int", 3)

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cZoneCheck
            $foo = GUICtrlRead($cZone)
            MsgBox(0, "Notify", $fooResult1[0])

    EndSwitch
WEnd

So I assigned fooResult1 to [1] to determine whether it was actually being assigned a value because calling the result in a msgbox without an array was resulting in 0 regardless, then I read up that if you call the result as an array, it would work. Did this with the add function and voila it worked! Then I tested the matchingmethod function and I get a :

Line 180 (File "..\SCRIPTNAME.au3":

MsgBox(0, "Notify", $fooResult1[0])
MsgBox(0, "Notify", #fooResult1^ ERROR

Error : Subscript used on non-accessible variable.

I'm wondering if this has anything to do with the includes in the DLL file? (Though I did link and include them properly I believe, added the include directory under C/C++ general, the lib directory in the linker general Additional Lib directories, and the .lib files under the Linker input additional lib files).

 

Anyone know what's going on here?

Share this post


Link to post
Share on other sites
roger911

Welp, can't edit the previous post... So basically I removed all the code inside the function, and just had return 999; in it. Still giving the same error, which leads me to believe the issue lies in the variable usage in the required variables. I've tried removing the using x lines, swapping everything to use std:: or cv::, issue persists, tried swapping "std::string" with "string" in the variable type declaration in the DLL call, issue persists. replaced void with void*, etc etc. Still no progress...

 

Are strings and void* not supported in DLL calls?

Share this post


Link to post
Share on other sites
TheXman
48 minutes ago, roger911 said:

Are strings and void* not supported in DLL calls?

@roger911

When you looked at the help file for the DllCall function, in the list of "types" did you see "void" or "string" as a valid type?  I didn't.  I saw "none" for void and either "str" or "wstr" for strings.  Maybe another thorough reading of the DllCall syntax is in order?  :)

https://www.autoitscript.com/autoit3/docs/functions/DllCall.htm

  • Thanks 1

Share this post


Link to post
Share on other sites
roger911

Thanks Xman, this helped me somewhat.

I fixed the Autoit code as per the reference, and when using flat words such as "foo" it seems to run fine, and returns -10 as no file was loaded. Then I input the pathing for "../img/Test/pngsearch.png" and ran it. Autoit Opened, waited for a second then closed with a return value of 0 as though it has completed it's task and has closed. After removing the special characters again it worked. I threw all the files in the same directory, and ran it again, then it ran and closed itself again.

 

This is pretty frustrating.

Share this post


Link to post
Share on other sites
TheXman

You're making progress and that's a good thing.   :thumbsup:

Not being able to see your updated AutoIt code makes it almost impossible to see whether the issue is in your C function or the AutoIt call.  If it is in your C code, that falls outside the scope of this forum but others may help you with that.  If it is an AutoIt issue, I'm sure I can help you get past it.

  • Thanks 1

Share this post


Link to post
Share on other sites
Danyfirex

Hello. Debug your code. make sure you get a valid path check inside your dll maybe using a messagebox, also share you dllcall to be sure if you're doing well.

 

Saludos

  • Thanks 1

Share this post


Link to post
Share on other sites
roger911
;$fooResult1 = DllCall("ITM.dll", "int", "MatchingMethod", "int", 1, "str", "pngsearch.png", "str", "lookfor.bmp")
$fooResult1 = "notfoo"
$fooResult1 = DllCall("ITM.dll", "str", "feedback", "str", "foo")


While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $cZoneCheck
            $foo = GUICtrlRead($cZone)
            MsgBox(0, "Notify", $fooResult1[0])

    EndSwit

Well, I decided to run everything in the same folder. The function is working but the portion in C/C++ was returning as though the files weren't loaded even though they were given proper filenames. To verify that the issue wasn't in C/C++ I decided to make a makeshift function which would accept a string then feed it back.

std::string feedback(std::string foo)
	{
		return foo;
	}

The program runs fine, and $fooResult1 is being assigned post "notfoo" assignment, however, on the message box, array 1-3, or no array. All turns up empty. This is leading me to believe that the string variables aren't being passed through to the DLL properly.

Share this post


Link to post
Share on other sites
Danyfirex
Posted (edited)

Hello use const char * in your dll.

also add cdecl in your dllcall return type value, check help file.

Saludos

 

Edited by Danyfirex

Share this post


Link to post
Share on other sites
roger911

Done, done, and done.

 

So, using OpenCV and image template matching, I've built a DLL which does an image search. This works!

 

Attached is the DLL (You may require the dependancy files/installation of OpenCV which you can get from sourceforge - https://sourceforge.net/projects/opencvlibrary/)

Source files for the DLL are in ITM.7z (ITM.h, ITM.cpp, ITM.def, stdafx.h, stdafx.cpp). If you want to compile it yourself, just make sure to install and link the openCV libs.

 

TYVM Dany and Xman!

 

 

ITM.dll

ITM.7z

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×