|
|
|||||||
![]() |
|
|
Thread Tools | Search this Thread | Display Modes |
|
|
#1 |
|
Registered User
Join Date: Jul 2007
Posts: 2
|
Hello, i have problem to pass my numeric parameters and to get the return value. i don't have all the possible situations regarding the parameters that CallDll accept from an external DLL.
Here is the function (inside the custom DLL) that i want to link: int myfunction(int myPort, int myResult); here is inside NC_Plugin.h: LPCTSTR GetParameter(LPCTSTR szParamName, HRESULT *pStatus = NULL); int GetParameter(int szParamName, int nValue); Here is inside an implemented function calling from CallDLL: int myPort,myMode; myPort = (int) pNCCommandParameters->GetParameter("Port"); myMode =(int) pNCCommandParameters->GetParameter("Mode"); int szReturn = proc(myPort,myMode); pNCCommandParameters->SetParameter("result", szReturn); How can i use the structure of HRESULT? How can i get the last parameter of my function as the variable to be return? |
|
|
|
|
|
#2 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
All parameters in SWF Studio plugins are strings.
If you're passing a parameter back to SWF Studio you have to convert it to a string first, like this... Code:
CString s; long myNumber = 12345; s.Format(L"%ld", myNumber); pNCCommandParameters->SetParameter(L"myNumber", s); When you're retrieving parameters passed to you from Flash they all come in as strings. If you need to work with real numeric values then you'll have to convert the string to a number so you can work with it, like this... Code:
CString s = pNCCommandParameters->GetParameter(L"Index"); long index = atol(s.GetString()); |
|
|
|
|
|
#3 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
creating custom plugin
Hi NorthCode,
I'm not sure if I should add to this thread or start a new one or if this belongs in another thread that I don't know about, but ... I have a few questions about CallDLL. I'm using this example as my template. I know I can call the dll function login with something like this: HELLO_FNPTR proc = (HELLO_FNPTR) GetProcAddress(m_pDLLModule, "login"); but function login in requires 3 parameters. How do I pass values to those parameters through GetProcAddress? Stephen |
|
|
|
|
|
#4 |
|
Registered User
Join Date: May 2003
Location: Ottawa
Posts: 416
|
GetProcAddress only gets you a pointer (the code address) of the function you requested, in this case "login".
To call the function, you'd do something like this: proc(param1, param2, param3); Your declaration for HELLO_FNPTR will have to match to match what "login" expects/returns. Also, don't forget to check that GetProcAddress didn't return NULL before trying to make the call. Trying to call NULL is an access violation, and nobody wants to do that. |
|
|
|
|
|
#5 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Ok I get it so far. But I'm not certain of the syntax.
You said something like this: proc(p1,p2,p3) So does that mean: LPCWSTR szReturn = proc(param1, param2, param3); ? Also you mentioned declaration for HELLO_FNPTR will have to match... So how do I change this if the type for param1 ... 3 are int, char, and pointer?: typedef LPCWSTR (*HELLO_FNPTR)(void); Thanks, Stephen |
|
|
|
|
|
#6 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
The conversion from function declaration to function pointer declaration is purely mechanical.
If you had a function declaration like this that you wanted to call Code:
LPCWSTR TheFunction(DWORD arg1, LPCWSTR argc, long arg3); Code:
typedef LPCWSTR (*THEFUNCTION_FNPTR)(DWORD, LPCWSTR, long); HOWEVER I think I've mentioned this a couple of times before... You only need to use GetProcAddress and a call through a function pointer if you're not sure the target DLL is going to be there at runtime. If you are shipping the DLL or requiring it to be there then you can just compile against the target DLLs LIB and H files and let the compiler and linker do all the hard work for you. Just wanted to make sure you're not making your life more complicated than it has to be
|
|
|
|
|
|
#7 |
|
Registered User
Join Date: Jul 2007
Posts: 2
|
Nothing special
Just analyse the source given in CALLDLL to know that it is quite easy to declare your external functions. It is important to know the exact prototype of every external functions. If not, the final exe will crash.
Example Extern DLL: LPCTSR GetVersionBox(char *IdBox); Example Integration with CallDLL: Code:
DECLARE_PARAMETERS(CCallDLL, GetVersionBox, "Call the DLL GetVersionBox function.");
OUT_PARAMETER(result, "The returned version of the keypad.");
IN_PARAMETER(IdBox, "The number of the keypad", "");
ERROR_CODE(1, "LoadLibrary() must have failed.");
ERROR_CODE(2, "GetProcAddress() failed.");
END_PARAMETERS;
IMPLEMENT_COMMAND(CCallDLL, GetVersionBox)
{
LPCTSTR myIdBox = "";
if (m_pDLLModule == NULL)
return 1;
typedef LPCTSTR (*GETVERSIONBOX_FNPTR)(LPCTSTR); //number of parameters
GETVERSIONBOX_FNPTR proc = (GETVERSIONBOX_FNPTR) GetProcAddress(m_pDLLModule, "GetVersionBox");
if (proc == NULL)
return 2;
myIdBox = pNCCommandParameters->GetParameter("IdBox");
LPCTSTR szReturn = proc((char * )myIdBox);
pNCCommandParameters->SetParameter("result", szReturn);
return S_OK;
}
|
|
|
|
|
|
#8 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Help from the forum
To anyone who view this,
I'm basically trying to integrate the Aladdin HASP function into my app. This is kind of related to another post about wrapping a SWFStudio app and it not working due to injecting code (http://www.northcode.com/forums/showthread.php?t=8273). So my question is has anyone done this with SWFStudio, create a NC Plugin with HASP SDK, and if so is anyone willing to share some sample code? I guess my problem is I'm new to Aladdin's SDK and my C++ is a bit rusty. So I guess this question is for both NC and Aladdin experienced people. Also, to anyone that reads this, FYI, according to NC they will add a feature in a later version so wrapping the app will be possible but it currently isn't possible to just wrap it. I'm trying to do this cheap and fast. Thanks for any input or suggestions. Stephen |
|
|
|
|
|
#9 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
To Northcode,
Now the dll function I'm trying to call is hasp_login which has 3 parameters: hasp_status_t HASP_CALLCONV hasp_login(hasp_feature_t feature_id, hasp_vendor_code_t vendor_code, hasp_handle_t * handle) Ok now I've declared, this: typedef LPCWSTR (*HASP_FNPTR)(hasp_feature_t, hasp_vendor_code_t, hasp_handle_t); I'm a bit confused after this: Using GetProcAddress: HASP_FNPTR proc = (HASP_FNPTR) GetProcAddress(m_pDLLModule, "hasp_login"); if (proc == NULL) return 2; ??? --> LPCWSTR szReturn = proc(pNCCommandParameters->GetParameter(L"param1")); Not using GetProcAddress: ??? --> LPCWSTR szReturn = hasp_login(???); Also if I'm trying to pass 3 parameters do I have to change this as well?: DECLARE_PARAMETERS(CCallDLL, hasp_login, L"Call the hasp_login function."); // defines the name of the plugin function, "Hello", and provides a description of what the function does OUT_PARAMETER(result, L"The returned value from the DLL."); // the only parameter is an output paramter called "result" that will be returned to Flash IN_PARAMETER(param1, L"The text to be reversed.", L""); // defines an input parameter (param1) that will be passed to the DLL "Reverse" function ERROR_CODE(1, L"LoadLibrary() must have failed."); // possible error this function can return ERROR_CODE(2, L"GetProcAddress() failed."); // possible error this function can return END_PARAMETERS; // end of the parameter block for the "Hello" function Should I add : IN_PARAMETER(param2, L"blah blah.", L""); IN_PARAMETER(param3, L"blah blah.", L""); Thanks for your help, Stephen |
|
|
|
|
|
#10 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
Let's get the declaration fixed first...
Code:
hasp_status_t HASP_CALLCONV hasp_login(hasp_feature_t feature_id, hasp_vendor_code_t vendor_code, hasp_handle_t * handle) ![]() Code:
typedef hasp_status_t (*HASP_FNPTR)(hasp_feature_t, hasp_vendor_code_t, hasp_handle_t); Code:
HASP_FNPTR pfn_hasp_login = (HASP_FNPTR) GetProcAddress(m_pDLLModule, "hasp_login"); hasp_feature_t feature_id = todo; // initialize this ! hasp_vendor_code_t vendor_code = todo; // initialize this ! hasp_handle_t * handle = todo; // initialize this ! hasp_status_t status = pfn_hasp_login(feature_id, vendor_code, vendor_handle); |
|
|
|
|
|
#11 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Thanks for the tips. I have a few more questions.
If I wanted to pass some values from the SWFStudio to the DLL how would I go about doing that? For example, if I had the feature_id value of 1 in the SWF file and wanted to pass that value to the DLL. Also when I get the return value from the DLL function is this the correct syntax? hasp_status_t status = pfn_hasp_login(feature_id, vendor_code, handle); pNCCommandParameters->SetParameter(L"result", (const hasp_status_t) status); Thanks in advance, Stephen |
|
|
|
|
|
#12 | |
|
Plugin Developer
Join Date: Jun 2002
Location: Germany
Posts: 2,409
|
Quote:
We canīt tell you how exactly to to this without knowing what kind of structure hasp_status_t is. Another caveat in your function pointer that Tim propably overlooked: The function signature of hasp_logindeclares a specific calling convention, HASP_CALLCONV . You must keep that in mind when declaring your function pointer, so typedef hasp_status_t (*HASP_FNPTR)(hasp_feature_t, hasp_vendor_code_t, hasp_handle_t); should be typedef hasp_status_t (HASP_CALLCONV* HASP_FNPTR)(hasp_feature_t, hasp_vendor_code_t, hasp_handle_t); depending on HASP_CALLCONV it might work without it, but you might as well get a runtime error if you build your dll with debug information |
|
|
|
|
|
|
#13 |
|
Registered User
Join Date: May 2003
Location: Ottawa
Posts: 416
|
.... or not. SetParameter is overloaded, and will also accept an int or, with the latest SDK, an __int64.
So, if hasp_status_t is not a structure, but rather a typedef for a numeric value, you can just cast it to be an int/__int64 as appropriate. |
|
|
|
|
|
#14 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
Thanks AGo, I missed the HASP_CALLCONV. I'm guessing it's for setting the calling convention used by the HASP DLL. Most likely it's __stdcall or something, but you'll find out very quickly if it's wrong / different from what the plugin is using
![]() To pass values from your SWF to the CallDLL you have to declare a function and an IN parameter for every value you want to pass. All the values you get passed from SWF Studio arrive as strings. You just have to convert them to whatever the HASP DLL wants before you make the call. |
|
|
|
|
|
#15 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Thanks gents for all your inputs.
I've got it to compile, can you double check my code: DECLARE_PARAMETERS(CCallDLL, hasp_login, L"Call the hasp_login function."); // defines the name of the plugin function, "Hello", and provides a description of what the function does OUT_PARAMETER(result, L"The returned value from the DLL."); // the only parameter is an output paramter called "result" that will be returned to Flash IN_PARAMETER(param1, L"The text to be reversed.", L""); // defines an input parameter (param1) that will be passed to the DLL "Reverse" function IN_PARAMETER(param2, L"The text to be reversed.", L""); // defines an input parameter (param1) that will be passed to the DLL "Reverse" function IN_PARAMETER(param3, L"The text to be reversed.", L""); // defines an input parameter (param1) that will be passed to the DLL "Reverse" function ERROR_CODE(1, L"LoadLibrary() must have failed."); // possible error this function can return ERROR_CODE(2, L"GetProcAddress() failed."); // possible error this function can return END_PARAMETERS; // end of the parameter block for the "Hello" function IMPLEMENT_COMMAND(CCallDLL, hasp_login) // marks the beginning of the implementation of the "Hello" function { if (m_pDLLModule == NULL) return 1; typedef hasp_status_t (HASP_CALLCONV* HASP_FNPTR)(hasp_feature_t, hasp_vendor_code_t, hasp_handle_t); hasp_feature_t hfeature_id = (hasp_feature_t)pNCCommandParameters->GetParameter(L"param1"); hasp_vendor_code_t hvendor_code = (hasp_vendor_code_t)pNCCommandParameters->GetParameter(L"param2"); hasp_handle_t hhandle = (hasp_handle_t)pNCCommandParameters->GetParameter(L"param3"); HASP_FNPTR pfn_hasp_login = (HASP_FNPTR) GetProcAddress(m_pDLLModule, "hasp_login"); hasp_feature_t feature_id = hfeature_id; hasp_vendor_code_t vendor_code = hvendor_code; hasp_handle_t handle = hhandle; hasp_status_t status = pfn_hasp_login(feature_id, vendor_code, handle); pNCCommandParameters->SetParameter(L"result", (const hasp_status_t) status); return S_OK; } now in the swf file I call this function like this: ... ssCore.Plugin.load({plugin:"CallDll", alias:"test"}); function onHello() { r = ssCore.test.hasp_login({param1:"0", param2:"0", param3:"0"}); if (r.success) { ssCore.App.showMsgBox({prompt:"call to 'Hello' returned: " + r.result}); } else { ssCore.App.showMsgBox({prompt:"call to 'Hello' failed: " + r.Error.description}); } } ... when I build and run my test I get: basically, specified method does not exist "ssCore.test.hasp_login" I put the CallDLL.dll in the plugins folder and the hasp.dll in the same folder as the executable. Any thoughts? Thanks for all your patients, obviously I'm new to this plugin thing... Thanks, Stephen |
|
|
|
|
|
#16 |
|
Plugin Developer
Join Date: Jun 2002
Location: Germany
Posts: 2,409
|
with which SWF Studio version do you compile?
If you put the plugin dll into SWF Studio´s plugin folder and select it in your SPF settings you do not need to call ssCore.Plugin.load, you should be able to use ssCore.callDLL from the beginning HOWEVER for debugging purpose, put both your plugin CallDLL.DLL and the hasp DLL into startdir:// of your app, and then use loadFromFolder and see if that gives you an error. do NOT select the plugin on the plugin tab or you´ll get an alias error ActionScript Code:
|
|
|
|
|
|
#17 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
I'm using Flash8.
I tried your suggested code. It was helpful in at least figuring out if the dll is loaded or not. Unfortunately I still get the same error: load ok ERROR: Specified method does not exist. "ssCore.test.hasp_login" Any thoughts? In case someone needs a demo dll, there is a public demo hasp dll available or I can send it. Thanks again, Stephen |
|
|
|
|
|
#18 |
|
Plugin Developer
Join Date: Jun 2002
Location: Germany
Posts: 2,409
|
Hmm, usually the compiler would shout at you if you have e.g. missed the declaration in the header file or used another name for your function somewhere,...
Try ssCore.Plugin.getCommands and getManifest to see which commands SWF Studio finds in your plugin. Now this is only a very vague guess, maybe try to rename your SWF Studio function name "hasp_login" to "hasplogin" maybe the underscore screws things up... your code looks good to me on first sight. |
|
|
|
|
|
#19 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Thanks AGo for your tips. I changed hasp_login to hasplogin and it seemed to work. I'm not sure if this would be considered a bug, but you might want to test this out NorthCode. I'm sure I'll have more questions coming.
Thanks again gents, Stephen |
|
|
|
|
|
#20 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Hey Northcode,
I have a question. Is it possible to return more then 1 result? There is this line: OUT_PARAMETER(result, L"The returned value from the DLL."); // defines an output parameter (result), where the result of the call to the DLL function will be returned to Flash which returns the value but can I create more of these like I can for the IN_PARAMETER? And if so, how do I modify this line to make it happen: pNCCommandParameters->SetParameter(L"result", (const hasp_status_t) status); Thanks, Stephen |
|
|
|
|
|
#21 |
|
Plugin Developer
Join Date: Jun 2002
Location: Germany
Posts: 2,409
|
sure it works exactly the same way as for the IN_PaRAMETERS
OUT_PARAMETER(result, L"The 1st returned value from the DLL."); OUT_PARAMETER(result2, L"The 2nd returned value from the DLL."); OUT_PARAMETER(result3, L"The 3rd returned value from the DLL.");.. . . . and then in the implementation pNCCommandParameters->SetParameter(L"result", (const hasp_status_t) status); pNCCommandParameters->SetParameter(L"result2", 42); //returns "42" as result2 pNCCommandParameters->SetParameter(L"result3", L"third result values goes here"); //returns the text as 3rd value |
|
|
|
|
|
#22 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
You can name the out parameters whatever you like (just in case that wasn't clear).
We'll check into the _ thing today and see what's going on. |
|
|
|
|
|
#23 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
I figured as much, but now my next question is this...
I have declared.. char* info; And when I call my function it returns a pointer (info). So for me to retrieve the information I call: pNCCommandParameters->SetParameter(L"result2", (const LPWSTR) &info); but when I actually print the result2 values using ssDebug.trace, I just get a bunch of questions marks and a few random characters. Basically info suppose to be a pointer to XML text. Any help would be appreciated. Thanks, Stephen |
|
|
|
|
|
#24 |
|
Registered User
Join Date: May 2003
Location: Ottawa
Posts: 416
|
The reason you're getting question marks is that your casting a single-byte character string to be a wide string. Casting makes your code compile, but doesn't change the nature of the data.
It would be better if your function returned a wide string (a WCHAR *), but if that's not possible, you can convert the data using the MultiByteToWideChar function. The reason you want to keep everything natively wide-character (Unicode) is that without this, you have very little chance of it working properly with more exotic character sets, like Russian, Korean or Chinese. |
|
|
|
|
|
#25 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Thanks for the tip. I understand the use of WCHAR, but I guess I'm getting confused in the pointers and how to convert it to WCHAR.
Here is basically a snippet of the code I'm working on: char* info; const char *format = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" "<haspformat root=\"hasp_info\">" " <hasp>" " <attribute name=\"id\" />" " </hasp>" "</haspformat>"; typedef hasp_status_t (HASP_CALLCONV* HASP_FNPTR)(hasp_handle_t, const char *, char**); HASP_FNPTR pfn_hasp_get_sessioninfo = (HASP_FNPTR) GetProcAddress(m_pDLLModule, "hasp_get_sessioninfo"); hasp_status_t status = pfn_hasp_get_sessioninfo(ghandle, const_cast<char*>(format), &info); pNCCommandParameters->SetParameter(L"result", (const hasp_status_t) status); pNCCommandParameters->SetParameter(L"result2", (const LPWSTR) &info); Thanks, Stephen |
|
|
|
|
|
#26 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
If you're doing this...
char* info; pNCCommandParameters->SetParameter(L"result2", (const LPWSTR) &info); then you don't understand the difference between a char and a wchar (or LPSTR and LPWSTR) and why a cast is not sufficient. You can easily cast one scalar type to another if you're ready to accept some possible loss of data or precision. There is no problem when you down cast a double to an int, the compiler just reinterprets the data, does the assignment to the new variable and you get on with your life. double d = 2.0 int i = (int)d; A char pointer points to an array of single byte values. A wchar pointer points to an array of double byte values. A simple reinterpretation of the data you're pointing to radically alters the state of the universe. When you cast a pointer, the data itself doesn't change like when you cast a scalar type, so now you're looking at square data through a round hole. There are cases where you can cast pointers and get away with it, this is not one of those times. To convert a char to a wchar you need to use the MultiByteToWideChar API function (as Dan already mentioned). You're basically going to double the size of the data and possibly even change some of the data, depending on the code page you use for the conversion. You just can't do that with a cast. |
|
|
|
|
|
#27 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Ok so I basically have to create a new variable using MultiByteToWideChar and convert info then pass that value or pointer to my swf file, is that right?
|
|
|
|
|
|
#28 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
Yup.
|
|
|
|
|
|
#29 |
|
Registered User
Join Date: Nov 2007
Posts: 52
|
Thanks for your help, it is working now. Here's the code snippet in case anyone else needs an example in the future with MultiByteToWideChar.
char* info; ... hasp_status_t status = pfn_hasp_get_sessioninfo(ghandle, const_cast<char*>(format), &info); wchar_t xmlOut[255]; ... MultiByteToWideChar(CP_ACP, 0, info, -1, xmlOut, sizeof(xmlOut) / sizeof(wchar_t)); ... pNCCommandParameters->SetParameter(L"result2", (const LPWSTR) xmlOut); Thanks all again, Stephen |
|
|
|
|
|
#30 |
|
Registered User
Join Date: May 2003
Location: Paris - France
Posts: 15
|
I tried to use this code (shown in previous post as example):
Code:
CString s = pNCCommandParameters->GetParameter(L"Index"); long index = atol(s.GetString()); error C2065: 'CString' : undeclared identifier Basically, I just want to retrieve a numeric parameter from Flash. I know that all parameters are always passed as text. Which header files are required to compile this code ? Can you give me a simple project example ? |
|
|
|
|
|
#31 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
CStirng is an internal string class we use in our plugins. It's part of the plugin library but we didn't expose the CString class itself.
There is an easier way though... Code:
long index = _wtol(pNCCommandParameters->GetParameter(L"index")); |
|
|
|
|
|
#32 | |
|
Registered User
Join Date: Nov 2010
Posts: 5
|
Quote:
here's my c++ code Code:
DECLARE_PARAMETERS(CSampleNotify, beepo, L"Bo my math");
IN_PARAMETER(text, L"The number.", L"");
OUT_PARAMETER(result, L"The output parameter for the command.");
END_PARAMETERS;
IMPLEMENT_COMMAND(CSampleNotify, beepo)
{
LPWSTR tt = pNCCommandParameters->GetParameter(L"text");
pNCCommandParameters->SetParameter(L"result", 60);
Beep(100,1000);
return S_OK;
}
Code:
var sd = ssCore.SampleNotify.beepo({text:"hello dll"});
ssCore.App.showMsgBox({icon:"question", buttons:"Ok", defaultButton:"button1", prompt:"Sd:"+sd.toString()+"\n Result:"+sd.result+"\n"+sd.hasOwnProperty("result")});
any ideas...really need help on this |
|
|
|
|
|
|
#33 |
|
Tim
Join Date: May 2001
Location: Ottawa
Posts: 11,873
|
See Dan's response in your other thread, I think he's onto something with the suggestion to use synchronous commands...
|
|
|
|