User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

QRCoder is an open source .Net assembly for creating QR Codes.  What we're going to do is wrap that with an assembly in SnapDevelop we can use from PowerBuilder.  First thing we need to do is create a .Net standard Class Library project in SnapDevelop.


Once we've done that we go into the Nuget Package Manager and install the QRCoder library.

In our wrapper assembly, we just need to add a few lines of code 

 public string GenerateQRCode(string qrText)   
     {  
       QRCodeGenerator qRCodeGenerator = new QRCodeGenerator();  
       QRCodeData qRCodeData = qRCodeGenerator.CreateQrCode(qrText, QRCodeGenerator.ECCLevel.Q);  
       PngByteQRCode pngByteQRCode = new PngByteQRCode(qRCodeData);  
       byte[] qrCodeBytes = pngByteQRCode.GetGraphic(20);  
       string qrCodeString = Convert.ToBase64String(qrCodeBytes);  
       return qrCodeString;  
     }  

A couple of things to note here.  first, if you look at the QRCoder documentation the sample they give involves the base QRCode class and converts the result to a bitmap.  Since I want to pass this back to PowerBuilder as a byte array or, as I've done here, as a Base64 encoded string, converting the result is a bitmap first is an intermediate step I don't want or need.  So I used the PngByteQRCode class instead to get a byte array   Second, I am converting the byte array to a Base64 string.  You can return a byte array directly from the assembly, and the .Net Importer will convert it to a blob automatically.  The issue is that for debugging purposes I can't see inside of a blob variable in the PowerBuilder debugger.  So if something goes wrong I'm not sure what I got back.  By passing back a Base64 encoded string to PowerBuilder and then converting it to a blob in PowerScript I have better insight when debugging.

After you've compiled that, lets switch over to PowerBuilder 2019 R3 and use it.  I created an target that contains a window that has a single line edit (sle_1) to enter text, a picture control (p_1_ to display the bitmap and a command button to run the script needed to generate the QR code image using the assembly.  Now we need to run the .Net Assembly importer to import our wrapper assembly.

As usual with a window this is going to call a .net assembly using the importer I do the following in order to facilitate error handling.

1.  Declare the .net assembly wrapper object as an instance variable on the window 

 nvo_qrgenerator inv_generator  

 2.  Instantiate the wrapper object in the open event and register the error handler to an event on the window 

 inv_generator = Create nvo_qrgenerator  
 inv_generator.of_seterrorhandler( this, 'assemblyerror')  

 3.  Destroy the instance variable in the close event of the window 

 Destroy inv_generator   

 4.  Create a custom event on the window to use as the error handler, and display any error messages relayed by the .net assembly wrapper 

 MessageBox ( "Error", inv_generator.is_errortext )  

 With that done we're ready to add the code to call the wrapper object and put the generated QR code in the picture control: 

 string          ls_text  
 string          ls_base64  
 blob          lblb_qrcode  
 CoderObject          co  
 p_1.visible = FALSE  
 ls_text = sle_1.Text  
 ls_base64 = inv_generator.of_generateqrcode( ls_text )  
 co = create CoderObject  
 lblb_qrcode = co.base64decode(ls_base64)  
 destroy co  
 p_1.setpicture( lblb_qrcode )  
 p_1.visible = TRUE  

 That's it.  Enter some text, click the command button and you've got a QR code

There's a bunch of options that I haven't touched on such as generating the QR code in color or adding a custom image to the center of the QR code.  I'll let you explore those on your own.   If you want to skip performing all these steps and just get started with the code, I've uploaded it to CodeXchange.

 

Comments (14)

  1. Eduardo Adriano

Hi Bruce,
Thank you very much for the code.

I'm trying to use the "qrcodedemo" api with PB 2019 R3. I changed the path of the dll file to my personal folder. Clicking to generate the QRCode that would run the DLL gives the error:

"Call GerenateQRCode failed.
Error Text: Error calling external object function generatedqrcode. Do not possible load the file or assembly 'QRCoder, Version = 1.4.1.0 ... "

I'm using Windows 10.
dotnet:
.netcore.app 5.0.5
.aspnetcore.app 5.0.5
.widnwosdesktop.app 5.0.5

dotnet sdk 5.0.202

I would like a help to resolve the error please.

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Bruce Armstrong

I'm not sure what you mean by "I changed the path of the dll file to my personal folder". Do you mean you changed the location that was included in the nvo_qrgenerator object?

Also, the QRCodeGenerator.dll file is just a wrapper around the QRCoder.dll. Do you have both in the location where you are attempting to load the assembly?

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. SHAMEEM KAKKAD

Hai Bruce,
What is the reason for the below error message?
I completed this route as save you explained at the top...
but, getting error...

"Could not load file or assembly 'netstandard Version=2.1.0.0, Culture-neutral,PublicKeyToken=cc7b13ffcd2ddd51' or one of its dependencies. The system cannot find the file specified"

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Bruce Armstrong    SHAMEEM KAKKAD

Generally this means your project is targeting one version of the .net framework and you've reference a library that targets a different version.

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. SHAMEEM KAKKAD    Bruce Armstrong

Let me check and thanks for your reply...

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Ramón San Félix Ramón

Great Bruce, thanks for your contributions to the community.

I have recently created a .Net library based on Zxing for the generation of barcodes of different types, including Qr.

The difference is that in addition to generating codes, it has the interesting option of reading them.

You can see my example here:

https://community.appeon.com/index.php/codeexchange/powerbuilder/309-qrcode-reader-and-qrcode-generator-with-zxing

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Tomas Beran

Hello
This is my first attempt to use SnapDevelop and here's my experience with this example. Information here may help beginners to avoid some try and fail attempts.
I use PB 2021
1. Create a new project based on Class Library .NET Standard as it's mentioned above.
2. In menu "Tools - Nuget Package Manager" -> "Manage Nuget Package for Solution" look for package "QRCoder". On the right side click the checkbox left to your project. Then click Install.
3. In menu "Project" -> "<your project> Properites" switch "Target framework" to ".NET Standard 2.0"
3. In your already generated .cs file insert row "using QRCoder;" at the end of the using block.
4. Put the code mentioned in the article into the pre-generated class.
5. Click menu Build -> Build Solution.
6. Create an export folder (somewhere, doesn't matter).
7. In Solution Explorer rclick the project, choose "Publish". Select a proper "target location", "configuration", "target framework" (again ".NET Standard 2.0"). Then follow the wizard. This step helps you solve dependencies.
8. Take all the files newly generated in the export folder from step 6. and copy them to the folder with your PB project.
9. Start PB. In menu Tools select ".NET DLL importer". Choose your DLL. Check whole DLL, click Import.
10. Move your newly created nvo from the app (project) library to a different library.
11. Remove the absolute path from the nvo instance variable named "is_assemblypath". Only filename must stay here for correct deployment.
11. Comment //inv_generator.of_seterrorhandler( this, 'assemblyerror') from the code in the article because there's no such method.
12. Open your PowerClient project. Go to 'External files' tab. Add all exported files here.

Notes:
Don't use p_1.OriginalSize attribute because picture object gets crazy after loading from blob through p_1.setpicture(lblb_blb).
Once you touch the .NET DLL in PB the DLL and the folder containing this DLL is being locked until you close PB. Never start SnapDevelop directly from PB because if you close PB it closes SnapDevelop.

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Uwe Schwan

Hello,

when i use this example within PB2022 and SnapDevelop2022, i only get a nugetpackage in the publish folder.
No "ORCodeGenerator.dll" and "ORCoder.dll" in the publish folder for the solution.
How can i use the PB .net DLL importer with a NuGet Package?

BR

Uwe

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Bruce Armstrong

Works fine for me. I downloaded the example, extracted it and deleted the the existing QRCodeGenerator.dll, both from the root directory and from the QRCodeGenerator\bin\Debug\netstandard2.0 directory. I then recompiled the sample using SnapDevelop 2022. I then copied the newly created QRCodeGenerator.dll in the QRCodeGenerator\bin\Debug\netstandard2.0 folder back into the root directory for the PowerBuilder application to find.

I then opened the PowerBuilder application, migrated it to 2022 and re-ran the .Net Importer. The only code change I had to make was to remove the code at line 2 of the open event of the w_main object. Apparently that line of code was a function that existed when I first wrote the demo, but is not in more recent versions of PowerBuilder. Once I did that, the sample ran fine.

P.S. I've uploaded a 2022 version of the sample to the original CodeXchange article.

  Attachments
Your account does not have privileges to view attachments in the comment
  Comment was last edited about 9 months ago by Bruce Armstrong Bruce Armstrong
  1. Jagamohan Dash

i got the error (could not load file or assembly 'QRcoder,version=1.4.3.0, Culture=neutral,PublicKeyToken=c4ed5b9ae8358a28'.A strongly-named assembly is required.(0x80131044)) at line 18 in function of_generateqrcode() of object nvo_myclass.... please anyone help me for this error to get the solution .

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Bruce Armstrong    Jagamohan Dash

Can you give any more details? I just grabbed the 2022 version of the sample code from CodeXchange, opened it in 2020 R2 GA and ran it and it ran without error.

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Adolfo Chairez Gallegos

I wrote in Visual Studio 2019 C# and SnapDevelop a library that generates a QR code, then a 64-bit application in PB 2022 R2 and it works fine on my computer where I have installed PowerBuilder 2022 R2 and Visual Studio 2019 (attached image), but when I install on a client computer it doesn't work (attached image). This is the list of PB2022 libraries that I deploy on the client, in fact I copied the whole folder: C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.281919\x64 to the client and it doesn't work, I can't find what could be missing, I can't find what I need to install on the client.

[Files]
Source: "C:\_DESARROLLO\EjemPB\GeneraQR\generaqr.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\_DESARROLLO\EjemPB\GeneraQR\GeneraQR.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\_DESARROLLO\EjemPB\GeneraQR\QRCoder.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\AtlAuxiliary.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\libcurl.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\msvcp140.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbacc.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\PBAccessibility.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbase.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbcompression.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbcrypt.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbdotnet.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbdotnetcoreinvoker.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbdotnetframeworkinvoker.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbdotnetinvoker.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbdpl.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbdwe.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbDWExcel12Interop.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbhttpclient.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbjson.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbmsoledbsql.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\PBMSTEXT.DLL"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbo10.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbo90.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pboauth.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbodb.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbora.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbPDF.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbpdfbuilder.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbrestclient.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbresource.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbribbonbar.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbshr.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbsysfunc.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbtheme.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbtra.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbUIS.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbvm.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbwebbrowser.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbXerces.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pdflib.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\vcruntime140.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\vcruntime140_1.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\xerces-c.dll"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\Program Files (x86)\Appeon\Common\PowerBuilder\Runtime 22.1.0.2819\x64\pbodb.ini"; DestDir: "{app}"; Flags: ignoreversion

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Tomas Beran

Hi,
Try to use LoadWithDotNetFramework function. LoadWithDotNet doesn't work for me in 2819.

  Attachments
Your account does not have privileges to view attachments in the comment
 
  1. Adolfo Chairez Gallegos    Tomas Beran

I solved it but it was not easy, I had to do it in Visual C# to generate QRCoder.dll, because SnapDevelop does not generate the QRCoder.dll library.

  Attachments
Your account does not have privileges to view attachments in the comment
 
There are no comments posted here yet