Page 1 of 2

using PB-made dll in MSVSC++12/13 project - unicode problem

Posted: Sun Sep 27, 2015 1:45 pm
by broozar
hi all,

i made a dll with PB and tested it with PB (OpenLibrary, GetFunction, CallFunctionFast), so i know it works at least in there. Now I want to use the DLL in a MSVSC++12/13 project, however I am not sure how to do this correctly. my steps so far:

- Properties>Linker>General>Additional Library Directories: path to both my lib and dll
- Properties>Linker>Input>Additional Dependencies: added the name of my .lib file

my procedure names from the DLL are still not highlighted, so I thought i'd write a header file. is that correct&necessary? if so, how is it supposed to look? I have a bunch of "extern"al function declarations, but I am unsure about the variable types, for instance is a PB string a char* or a string, is a PB-int equivalent to a c++-int, and so forth.

with the custom header file, I am getting an "unresolved external symbol LNK2019" error on my first custom function call.

thanks in advance

Re: using PB-made dll in MSVSC++12/13 project

Posted: Sun Sep 27, 2015 2:14 pm
by broozar
i now have

Code: Select all

extern "C" {
    int __stdcall functionname ( const char* parametername, [...]);
    [...]
}
does that look correct to you? it compiles, but for some reason the string i plug into const char* parametername does not appear to get through to the plugin.

Re: using PB-made dll in MSVSC++12/13 project

Posted: Sun Sep 27, 2015 11:08 pm
by broozar
ok, i really think the problem lies in my "const char* parametername". I try to pass a windows file path to my PB-made DLL ("D:\something\somethingelse"), and since backslashes have to be escaped in C/C++ strings, I use ("D:\\something\\somethingelse"). However the DLL does not find the folder.

with my own dll test program written in PB, i can successfully call my path using CallFunctionFast(function, @"D:\something\somethingelse"), completely without escaping anything.

what's going on here? any ideas?

Re: using PB-made dll in MSVSC++12/13 project

Posted: Mon Sep 28, 2015 6:23 am
by TI-994A
broozar wrote:I try to pass a windows file path to my PB-made DLL ("D:\something\somethingelse")...However the DLL does not find the folder.
First, ensure that the DLL is actually receiving the properly formatted path string. Give this example a try:

1. Create a test DLL, DLL Example, as follows:

Code: Select all

; DLL Example.dll / DLL Example.lib
ProcedureDLL MyFunction(filePath.s)
  MessageRequester("Received String:", filePath, 0)
EndProcedure
2. Add these two lines into either the header (.h) or source (.cpp) file of the VS2013 project:

Code: Select all

#pragma comment (lib, "DLL Example")   //no file extension required
extern "C" __declspec(dllimport) void _stdcall MyFunction(char* filePath);
3. Place the function anywhere in the source (.cpp) code, like so:

Code: Select all

MyFunction("D:\\something\\somethingelse\\*.*");
Important:
1. The DLL should be compiled with UNICODE disabled.
2. Both the PureBasic DLL and the C/C++ EXE must be compiled under the same architecture (either both 32bit, or both 64bit).
3. Both the generated .DLL and .LIB files should be in the VS2013 project source folder (no additional link/reference settings required).

Hope it works! :wink:

Re: using PB-made dll in MSVSC++12/13 project

Posted: Mon Sep 28, 2015 8:45 am
by broozar
thanks for your reply!
TI-994A wrote:
broozar wrote:1. The DLL should be compiled with UNICODE disabled.
uh-oh. that was unexpected. with the unicode flag set, i get this lovely string for a file path:

Image

if i disable unicode, i get at least the file path right. however i believe i do need that flag: the library is actually a translation helper for 26 languages, including non-ascii sets like chinese, russian, korean, and thai. i read my strings from utf-8 encoded XML files and need to return similarly encoded strings.

to clarify, the architecture of it all is this:
- one DLL (made with MSVS) acts as a plugin for another program. it sends the file path string as a parameter to the PB-made DLL as part of the init procedure
- this PB-made DLL gets the string, looks the folder up, and hopefully finds some utf-8 XML files in there. those files are read in and transformed
- the MSVS DLL can now call the PB-DLL and ask for random strings which could include non-ascii characters: [A-Z_] in, [.] out.

how can the absence of the unicode flag be reconciled with my need for utf-8 strings?
and: why does it work with unicode if i do not call the same thing from a MSVS DLL, but another PB program through CallFunctionFast?

PS: I already went through the MSVS project configuration properties > general > character set and switched it to unicode, no change. the "chinese" path string is the same.

Re: using PB-made dll in MSVSC++12/13 project

Posted: Mon Sep 28, 2015 9:31 am
by TI-994A
broozar wrote:...however i believe i do need that flag...
In that case, try this:

Code: Select all

ProcedureDLL MyFunction(filePath.s)
  filePath = PeekS(@filePath, -1, #PB_UTF8)
  MessageRequester("Received String:", filePath, 0)
EndProcedure
This would allow UNICODE compilation; no more Chinese characters!. :wink:

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Mon Sep 28, 2015 12:04 pm
by broozar
great, that seems to be a step in the right direction. i now override all string-arguments in the procedures with your PeekS-UTF8 tip, and it seems to work: all strings get to the DLL intact.
since i also have strings for return values, i need to do the same thing in reverse, as the output is equally garbled right now. i tried the same PeekS with UTF-8 in ProcedureReturn, however it returns a number... any tips?

all those changes also broke the DLL tester i wrote in PB. now the path is broken in there - not chinese, but stops after the first character. is there no universal solution, like working in unicode from front to back?

PS: i read on stackoverflow that windows/.net unicode is really utf-16, and so my utf-8 strings are causing problems. what confuses me is that the error occurs before i ever open any utf-8 encoded files, the problem occurs when sending a string from one unicode DLL to the next. i'd love to understand why this happens. when PB talks about unicode, do they mean UTF-8, UTF-16, or does it depend on the platform, like UTF-16 for Windows and UTF-8 for Linux?

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Mon Sep 28, 2015 3:18 pm
by TI-994A
broozar wrote:...since i also have strings for return values, i need to do the same thing in reverse, as the output is equally garbled right now.
1. Change the PureBasic DLL code as follows:

Code: Select all

ProcedureDLL.s MyFunction(filePath.s)
  Static returnString.s
  returnString = "PureBasic DLL: the file path is " + PeekS(@filePath, -1, #PB_UTF8)
  ProcedureReturn returnString
EndProcedure
2. Change the function declaration to:

Code: Select all

extern "C" __declspec(dllimport) char* _stdcall MyFunction(char* filePath);
3. Call the function like so:

Code: Select all

char* response = MyFunction("C:\\something\\something\\*.*");
MessageBox(NULL, LPCWSTR(response), L"From the DLL", MB_OK);
Now, the DLL returns the string that it receives, and the C/C++ program displays the response in a message box. :wink:


EDIT: defined the return string as static, per Fred's advice. :)

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Mon Sep 28, 2015 3:34 pm
by Fred
If you return a string, you should return a static string, or it could have problem as the string has been freed before leaving the procedure.

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Mon Sep 28, 2015 4:00 pm
by TI-994A
Fred wrote:If you return a string, you should return a static string, or it could have problem as the string has been freed before leaving the procedure.
Thanks for the pointer, Fred. Something that I'm not aware of. :)

Code edited accordingly.

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Mon Sep 28, 2015 4:59 pm
by Fred
It's still wrong, you have the return only the static string :)

Code: Select all

ProcedureDLL.s MyFunction(filePath.s)
  Static returnString.s
  returnString = "PureBasic DLL: the file path is " + PeekS(@filePath, -1, #PB_UTF8)
  ProcedureReturn returnString
EndProcedure

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Mon Sep 28, 2015 9:06 pm
by broozar
thanks for all the help! unfortunately, I have to be difficult as I can't get it to work. since it's no secret what I am working on, i will share some more code.

from the header:

Code: Select all

extern "C" {
	__declspec(dllimport) int __stdcall pg_init (const char* XMLFOLDER, const char* SCHEME, int VERSION);
	__declspec(dllimport) int __stdcall pg_isLanguageAvailable(const char* LANGCODE);
	__declspec(dllimport) const char* __stdcall pg_translate (const char* LANGCODE, const char* CODESTRING, int bLC);
	__declspec(dllimport) const char* __stdcall pg_translateCompound (const char* LANGCODE, const char* CODESTRING, int bLC);
}
my original question was about "const char* XMLFOLDER", which is the filepath that was not transmitted correctly. now, pg_translate and pg_translateCompound are giving me trouble, as they return nonsense.

from the "host" DLL:

Code: Select all

	//type conversion
	const char* lc = sLangcode.GetStringValue();
	const char* pc = sPolyglotCode.GetStringValue();
	bool bl = bLowercase.GetBooleanValue();

	const char* trans = pg_translate(lc, pc, bl);
	stranslatedString.SetStringValue(trans);
- I feed (ASCII only) sLangcode and sPolyglotCode to the dll, and convert those strings into const char* through the host program function GetStringValue()
- those are then plugged into the pg_translate function as defined in the header
- since I need to send the result back to the host program through SetStringValue which only accepts const char*, the return of pg_translate is also supposed to be of that type

from the PB DLL:

Code: Select all

; -- EXPORT -------------------------------------------------

; translated string to return
Global pg_returnTranslatedString.s = ""


; -- LOCALS --------------------------------------------------

Structure pg_langstruct
  langstring.s
  version.i
  location.s
EndStructure

Structure pg_dict
  Map dict.s()
EndStructure

Global NewMap availableLanguages.pg_langstruct()
Global NewMap languageDict.pg_dict()

Global pg_bInit = 0

; -- more preocedures here -> shortened

; translate string from code string
ProcedureDLL.s pg_translate(LANGCODE.s, CODESTRING.s, bLC.i)
  Static pg_returnTranslatedString.s
  
  LANGCODE = PeekS(@LANGCODE, -1, #PB_UTF8)
  CODESTRING = PeekS(@CODESTRING, -1, #PB_UTF8)
  
  If pg_bInit = 1
    If FindMapElement(languageDict(), LANGCODE)
      If bLC = 0
        pg_returnTranslatedString = languageDict(LANGCODE)\dict(CODESTRING)
      Else
        pg_returnTranslatedString = LCase(languageDict(LANGCODE)\dict(CODESTRING))
      EndIf
    Else
      pg_returnTranslatedString = "NOCODE"
    EndIf
  Else
    pg_returnTranslatedString = "NOINIT"
  EndIf
  
  ProcedureReturn PeekS(@pg_returnTranslatedString, -1, #PB_UTF8)
EndProcedure
The PB docs for DLLs state that all outgoing strings need to be declared as globals, but now with the static declaration in the function, is that still true? is there a possible conflict?
PS: the line MessageBox(NULL, LPCWSTR(response), L"From the DLL", MB_OK); does not seem to work at all for me. LPCWSTR does not accept the type from "response" as argument, and the literal L also throws an error.

EDIT: just saw fred's reply, "ProcedureReturn pg_returnTranslatedString" also gives no good result

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Tue Sep 29, 2015 3:30 am
by TI-994A
broozar wrote:...I can't get it to work. since it's no secret what I am working on, i will share some more code.
A little vague, especially when you seem to be dealing with multiple libraries. A little more code would help to put things in some perspective; at the very least, the full or working portions of the procedures involved, along with all their global dependencies. Alternatively, if you'd like, just zip the whole project up.

I'd be happy to look it over, and try to help out to the best of my abilities. :)

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Tue Sep 29, 2015 4:07 am
by TI-994A
Fred wrote:It's still wrong, you have the return only the static string :)
Right; the temp string as well. :lol:

Thanks again, Fred.

Re: using PB-made dll in MSVSC++12/13 project - unicode prob

Posted: Tue Sep 29, 2015 4:48 am
by TI-994A
Here are some points based on what you've provided.

When the pg_translate() function is called here:

Code: Select all

const char* trans = pg_translate(lc, pc, bl);
stranslatedString.SetStringValue(trans);
make sure that the DLL is receiving the values lc, pc, bl properly; perhaps by using message requesters to display them:

Code: Select all

ProcedureDLL.s pg_translate(LANGCODE.s, CODESTRING.s, bLC.i)
  Static pg_returnTranslatedString.s

  MessageRequester("Param 1:", PeekS(@LANGCODE, -1, #PB_UTF8), 0)
  MessageRequester("Param 2:", PeekS(@CODESTRING, -1, #PB_UTF8), 0)
  MessageRequester("Param 3:", Str(bLC), 0)
  ...
  ...
If they are, simply return the result like so:

Code: Select all

  ...
  ...
  ProcedureReturn pg_returnTranslatedString
EndProcedure
I'm not familiar with the string library that you're using, but you should be able to assign the returned string directly to a string variable.