Entity Framework Error in Access VBA - "The specified named connection is either not found in the configuration..." - vba

I have an Access VBA project from where I refer to a COM Interop .TLB written in C#. This C# code simply queries the SQL Server database and returns values via a simple LINQ-to-Entity query.
I'm getting the same error mentioned in this question:
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid
However, in my case, it is a Access VBA in a .ADP application that refers to my .Net 4.0 TLB, instead of another .Net project.
I'm aware that if it were another .Net project, I could add the EF connection string XML in its app.config or web.config. But what is the fix if my 'calling' application is Access 2003 VBA?
Here's the VBA code that calls the .Net code
Dim CandidatePassword As String
Dim abc As New MISHash.Password
Dim PasswordStatus As Boolean
CandidatePassword = InputBox("Enter your password")
PasswordStatus = abc.IsValidPassword("myusername", CandidatePassword) ' FAILS HERE
If PasswordStatus Then
MsgBox "Password valid."
Else
MsgBox "Password failed."
End If
Please help. Thank you.
Update: Here is my C# code
using System.Linq;
using System.Runtime.InteropServices;
namespace MISHash
{
public class Password
{
public Password()
{
}
[ComVisible(true)]
public void HashAndSave(string SomePassword)
{
string hashed = BCrypt.HashPassword(SomePassword, BCrypt.GenerateSalt(12));
//save the hashed password in the database
}
[ComVisible(true)]
public bool IsValidPassword(string CandidateUserName, string CandidatePassword)
{
string OriginalHashedPassword;
using (MyDBEntities mycontext = new MyDBEntities())
{
OriginalHashedPassword = (from usr in mycontext.Users
where usr.UserName.Equals(CandidateUserName)
select usr.Password).FirstOrDefault();
}
bool matches = BCrypt.CheckPassword(CandidatePassword, OriginalHashedPassword);
return matches;
}
}
}

See this similar question:
Can I use / access the app.config from .net code, when called via COM
These two seem like your best options:
Manually create a secondary AppDomain
Convert to a VSTO project
Edit
You can also try passing a hard-coded connection string in the constructor:
MyDBEntities mycontext = new MyDBEntities("Server=.\SQLEXPRESS;Database=School;Trusted_Connection=true;Integrated Security=True;MultipleActiveResultSets=True"))

Related

Using CefSharp with introp to embed in Microsoft Access Form

I have built new C# class library (user control) using CefSharp (it compiles with no errors) to use it in ms access form but when I try to embed in the form i get the following error:
and did not get error all the times, sometimes works fine, and when I try to embed in excel and I get this error:
I developed this library using:
Visual Studio 2013
Dot Net Framework 4.5.2
CefSharp 53.0.0
and this is the main part of my code:
public void InitBrowser()
{
var settings = new CefSettings();
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (!Cef.IsInitialized)
{
settings.BrowserSubprocessPath = Path.Combine(assemblyFolder, "CefSharp.BrowserSubprocess.exe");
if (Cef.Initialize(settings))
{
browser = new ChromiumWebBrowser("url");
}
}
this.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
}
What is the problem in this scenario?
Thanks in advance.

Compilation error: object library invalid or contains references to object definitions that could not be found

I want to import some data from an Oracle Database, but I don't want to leave the Password on the macro, as it is very easy to access. Then I found this code to hide myconnection string, which works pretty well, at least on my PC. I created a .dll of the next code so that the database data is not available for users.
using ADODB;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace HiddenConnectionString
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("2FCEF713-CD2E-4ACB-A9CE-E57E7F51E72E")]
public interface IMyServer
{
Connection GetConnection();
void Shutdown();
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("57BBEC44-C6E6-4E14-989A-B6DB7CF6FBEB")]
public class MyServer : IMyServer
{
private Connection cn;
private string cnStr = "Provider=MSDAORA.1;Password=YourPass;User ID=YourID;Data Source=IP:Port";
public MyServer)(
{
}
public Connection GetConnection()
{
cn = new Connection();
cn.ConnectionString = cnStr;
cn.Open();
return cn;
}
public void Shutdown()
{
cn.Close();
}
}
}
The next code is the one that I am trying to run:
Option Explicit
Sub Main()
Dim myCn As MyServer
Set myCn = New MyServer
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
'Consumos
rs.Open "select * from tablename, myCn.GetConnection
Sheets.Add After:=ActiveSheet
Range("A2").CopyFromRecordset rs
rs.Close
myCn.Shutdown
Set rs = Nothing
Set myCn = Nothing
End Sub
I've been trying to make it work on other computers but when I run the testing code on them i get this error:
Compilation error: object library invalid or contains references to object definitions that could not be found
So it seems like the library hasn't been imported, but when I check on the reference list, my "hiddenconnectionString.dll" is activated, so I don't know what it going on.
Can someone give me some advice on how to make it work? Any help is welcome. Thanks :D
Sounds like the dll is only installed on your machine. Items in the reference list are not imported and/or stored in the VBA. They need to be present on each host machine.
I'm not sure that hidden connection strings are a good idea. Security by obscurity is generally discouraged, as often it can be bypassed by anyone willing to invest enough time.
This design also uses a shared UID and PWD. With each user sharing an account you lose the ability to audit who did what.
Where possible, I'd always recommend providing each user with their own account.

How can I Write on 64bit registry? [duplicate]

I'm trying to insert some simple registry keys using Microsoft.Win32.RegistryKey in c# but the path automatically changes from:
HKEY_LOCAL_MACHINE\SOFTWARE\Test
to
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Test
I tried google but I only get some vague and confusing results. Has anyone dealt with this issue before? Some example code would be much appereciated.
You can use RegistryKey.OpenBaseKey to solve this problem:
var baseReg = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var reg = baseReg.CreateSubKey("Software\\Test");
Under WOW64, certain registry keys are redirected (SOFTWARE). When a 32-bit or 64-bit application makes a registry call for a redirected key, the registry redirector intercepts the call and maps it to the key's corresponding physical registry location. For more information, see Registry Redirector.
You can use the RegistryView Enumeration on RegistryKey.OpenBaseKey Method to open the 32-bit view explicitly and access HKLM\Software\ directly.
I don't know how to solve it using a .reg file. But only in a BAT file, as follow:
You must add /reg:64 at the end of the command line.
ex:
REG ADD "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\Background" /v "OEMBackground" /t REG_DWORD /d 0x00000001 /f /reg:64
Source: Wow6432Node and how to Deploy Registry settings to 64 bit systems via Sccm
Here is the working code I have developed to both read and write ONLY the 32-bit registry. It works in both 32-bit and 64-bit applications. The 'read' call updates the registry if the value is not set, but it is very obvious how to remove that. It requires .Net 4.0, and uses the OpenBaseKey/OpenSubKey methods.
I currently use it to allow a 64-bit background service and a 32-bit tray application to access the same registry keys seamlessly.
using Microsoft.Win32;
namespace SimpleSettings
{
public class Settings
{
private static string RegistrySubKey = #"SOFTWARE\BlahCompany\BlahApp";
public static void write(string setting, string value)
{
using (RegistryKey registryView = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
using (RegistryKey registryCreate = registryView.CreateSubKey(RegistrySubKey))
using (RegistryKey registryKey = registryView.OpenSubKey(RegistrySubKey, true))
{
registryKey.SetValue(setting, value, RegistryValueKind.String);
}
}
public static string read(string setting, string def)
{
string output = string.Empty;
using (RegistryKey registryView = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32))
using (RegistryKey registryCreate = registryView.CreateSubKey(RegistrySubKey))
using (RegistryKey registryKey = registryView.OpenSubKey(RegistrySubKey, false))
{
// Read the registry, but if it is blank, update the registry and return the default.
output = (string)registryKey.GetValue(setting, string.Empty);
if (string.IsNullOrWhiteSpace(output))
{
output = def;
write(setting, def);
}
}
return output;
}
}
}
Usage:
Put this in it's own class file (.cs) and call it as such:
using SimpleSettings;
string mysetting = Settings.read("SETTINGNAME","DEFAULTVALUE");

Deploying SSRS RDL files from VB.Net - Issue with shared datasources

I am currently developing a utility to help automate our report deployment process. Multiple files, in multiple folders, to multiple servers.
I am using the reportservice2010.asmx web service, and I am deploying my files to the server - so most of the way there.
My issue is that I have shared data sets and shared data sources, which are deployed to individual folders, separate to the report folders. When the deployment occurs the web service looks locally for the data source rather than in the data source folder, giving an error like:
The dataset ‘CostReduction’ refers to the shared data source ‘CostReduction’, which is not
published on the report server. The shared data source ‘CostReduction’ must be published
before this report can run.
The data source/set has been deployed and the report functions correctly but I need to suppress these error messages as they may be hiding other actual errors.
I can hard code a lookup that checks if the data source/set exists and manually filter them via that, but it seems very in-efficient. Is there any way I can tell the web service where to look for these files or another approach that other people have used?
I'm not looking at changing the reports so the data source is read from
/DataSources/DataSourceName
as there are lots of reports and that's not how our existing projects are configured.
Many thanks in advance.
I realize you are using VB, but perhaps this will give you a clue if you convert it from C# to VB, using one of the translators on the web.
Hopefully this will give you a lead in the right direction.
When All the reports in a particular folder, referred to here as the 'parent folder', all use the same Shared Data source, I use this to set all the reports to the same shared Data Source (in this case "/DataSources/Shared_New")
using GetPropertiesSample.ReportService2010;
using System.Diagnostics;
using System.Collections.Generic; //<== required for LISTS
using System.Reflection;
namespace GetPropertiesSample
{
class Program
{
static void Main(string[] args)
{
GetListOfObjectsInGivenFolder_and_ResetTheReportDataSource("0_Contacts"); //<=== This is the parent folder
}
private static void GetListOfObjectsInGivenFolder_and_ResetTheReportDataSource(string sParentFolder)
{
// Create a Web service proxy object and set credentials
ReportingService2010 rs = new ReportingService2010();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
CatalogItem[] reportList = rs.ListChildren(#"/" + sParentFolder, true);
int iCounter = 0;
foreach (CatalogItem item in reportList)
{
iCounter += 1;
Debug.Print(iCounter.ToString() + "]#########################################");
if (item.TypeName == "Report")
{
Debug.Print("Report: " + item.Name);
ResetTheDataSource_for_a_Report(item.Path, "/DataSources/Shared_New"); //<=== This is the DataSource that I want them to use
}
}
}
private static void ResetTheDataSource_for_a_Report(string sPathAndFileNameOfTheReport, string sPathAndFileNameForDataSource)
{
//from: http://stackoverflow.com/questions/13144604/ssrs-reportingservice2010-change-embedded-datasource-to-shared-datasource
ReportingService2010 rs = new ReportingService2010();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
string reportPathAndName = sPathAndFileNameOfTheReport;
//example of sPathAndFileNameOfTheReport "/0_Contacts/207_Practices_County_CareManager_Role_ContactInfo";
List<ReportService2010.ItemReference> itemRefs = new List<ReportService2010.ItemReference>();
ReportService2010.DataSource[] itemDataSources = rs.GetItemDataSources(reportPathAndName);
foreach (ReportService2010.DataSource itemDataSource in itemDataSources)
{
ReportService2010.ItemReference itemRef = new ReportService2010.ItemReference();
itemRef.Name = itemDataSource.Name;
//example of DataSource i.e. 'itemRef.Reference': "/DataSources/SharedDataSource_DB2_CRM";
itemRef.Reference = sPathAndFileNameForDataSource;
itemRefs.Add(itemRef);
}
rs.SetItemReferences(reportPathAndName, itemRefs.ToArray());
}
}
To Call it I use this in the 'Main' Method:
GetListOfObjectsInGivenFolder_and_ResetTheReportDataSource("0_Contacts");
In this case "0_Contacts" is the parent folder, itself located in the root directory, that contains all the reports for which I want to reset their DataSources to the new Shared DataSource. Then that Method calls the other method "ResetTheDataSource_for_a_Report" which actually sets the DataSource for the report.

Accessing COM add-in code from VBA

I have created a COM add-in for Excel 2003 using Visual Studio 2005 Tools for Office. The add-in code looks like this:
[Guid("EAC0992E-AC39-4126-B851-A57BA3FA80B8")]
[ComVisible(true)]
[ProgId("NLog4VBA.Logger")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class Logger
{
public double Debug(string context, string message)
{
Trace.WriteLine(message);
return message.Length;
}
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory + #"\mscoree.dll", RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type, "Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(#"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(#"}\");
s.Append(subKeyName);
return s.ToString();
}
}
I've set the project to register for COM interop, and I've registered the DLL with:
regasm.exe /tlb NLog4VBA.dll
When I open Excel, I go to Tools -> Add-Ins, click Automation, and add NLog4VBA.Logger. I can then go to Insert -> Function, pick NLogVBA.Logger from the list of categories, and choose Debug.
The end result is a cell with contents like:
=Debug("My Context","My Message")
... and a displayed value of:
10
This is all as it should be. In my VBA code, I can go to Tools -> References and add NLog4VBA. I then add the following code to a button on my sheet:
Private Sub CommandButton1_Click()
Application.COMAddIns("NLog4VBA.Logger").Object.Debug "My Context", "My Message"
End Sub
This fails, because COMAddIns("NLog4VBA.Logger") fails with:
Run-time error '9': Subscript out of range
Could someone please tell me what I need to do to make the Debug() method accessible to my VBA code (which is more useful to me than being able to call the method from within a cell)?
I'm sure I'm missing something simple here.
Edited 2010/09/07: I've updated the code snippet to include the [ProgId] attribute as suggested below by Jim; the problem persists. I can see the object in registry:
[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}]
#="NLog4VBA.Logger"
[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\Implemented Categories]
[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}]
[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\InprocServer32]
#="C:\\WINDOWS\\system32\\mscoree.dll"
"ThreadingModel"="Both"
"Class"="NLog4VBA.Logger"
"Assembly"="NLog4VBA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="file:///C:/projects/nlog4vba/NLog4VBA/bin/Debug/NLog4VBA.dll"
[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\InprocServer32\1.0.0.0]
"Class"="NLog4VBA.Logger"
"Assembly"="NLog4VBA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="file:///C:/projects/nlog4vba/NLog4VBA/bin/Debug/NLog4VBA.dll"
[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\ProgId]
#="NLog4VBA.Logger"
[HKEY_CLASSES_ROOT\CLSID\{EAC0992E-AC39-4126-B851-A57BA3FA80B8}\Programmable]
Also, the ProgID is visible in the Add-Ins dialog:
I still have no idea why this isn't working :-(
The COMAddIns collection is either indexed via a numerical index, or via a string that is the ProgId of the desired component. Make sure that your ProgId is actually "NLog4VBA.Logger" (via the ProgId attribute in .NET) and verify that the object is registered with this id (which you can easily check in the registry, searching for your assigned GUID).
It turns out that my VBA code was quite wrong; here is the answer courtesy Jan Karel Pieterse:
I think you would need to do something
like this:
Private Sub CommandButton1_Click()
'Declare an object variable using the referenced lib.
'if all is well, intellisense will tell you what the proper object name is:
Dim objLogger as NLog4VBA
'Create an instance of the object
Set objLogger = New NLog4VBA
'Now use the object
objLogger.Object.Debug "My Context", "My Message"
End Sub