We have a .NET DLL that contains several COM classes and objects that partner companies can use. We currently use regasm to register the COM classes in the registry. This has worked for years.
We now want to get rid of the COM registration and use side by side assemblies. I am currently trying to make this transition, but I seem to fail on the finish line. We deliver a sample application in C++ that uses our COM classes, and I try to get it to run without COM registration.
.NET DLL
In our .NET DLL, I have a class like this:
namespace MyNamespace
{
[ComVisible(true)]
[Guid("ef828ade-b459-4446-80db-956715588601")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MyVendor.MyClass")]
public partial class MyClass
{
}
}
Application assembly
The C++ sample application that shall work with this COM class has a manifest like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="x86"
publicKeyToken="6595b64144ccf1df"
language="*" />
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32"
name="MyComDll.X"
version="1.0.0.0" />
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"
uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
DLL assembly
And the .NET DLL itself has a manifest to expose the COM class to the outside world:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity type="win32"
name="MyComDll.X"
version="1.0.0.0" />
<file name="MyComDll.dll">
<comClass description="MyVendor.MyClass"
clsid="{ef828ade-b459-4446-80db-956715588601}"
progid="MyVendor.MyClass.1"
threadingModel="Both">
<progid>MyVendor.MyClass</progid>
</comClass>
</file>
</assembly>
Using COM
I obviously use proxy names in my code samples above, but I made sure the all names in the original code are valid.
In our sample C++ code, we are getting the CLSID and creating the instance of the class this way:
HRESULT hr = CLSIDFromProgID(OLESTR("MyVendor.MyClass"), &clsid);
hr = CoCreateInstance(clsid, nullptr, CLSCTX_SERVER, IID_IDispatch, (void**)(&_pMyClass));
What goes wrong
I use some debug output to check the GUID that was returned from CLSIDFromProgID() and to check the return value. If the COM class is registered using regasm, the return value is S_OK and clsid is the same GUID that I specified in my .NET DLL for the class.
However, if I remove the COM registration and use the side by side assemblies with manifests as shown above, I also get the S_OK return value, but the GUID is something entirely different, and therefore I cannot create an instance of this class. I have not found the GUID I get from CLSIDFromProgID() anywhere - neither in the registry nor in my development solution.
Do you have any idea what I made have done wrong?
I know that my C++ sample application works in general very well with our COM objects, because it works flawless, if the COM classes are registered.
I checked every part of the manifests I created with Microsoft's specification and various guides.
I do not get any SideBySide errors in the Windows Event log, so I know that the manifests are properly formatted.
I do get an S_OK from CLSIDFromProgID(), so I know the ProgID is found - it just delivers the wrong CLSID.
I used the function StringFromCLSID() to compare the CLSID that was found by `CLSIDFromProgID().
First of all, I want to thank Joseph Willcoxson and Remy Lebeau for pushing me in the right direction!
I had a couple of minor issues in my manifests that I could resolve one after another. The big mistake I made was taking the assumption that a CLSID that I get from CLSIDFromProgID is the same as the one I specified in my .NET COM class. After it was pointed out that is not necessarily the case, I did not waste any further time and checked why calling CoCreateInstance failed. It turned several iterations of online research and testing to figure out the mistakes I made.
As Joseph pointed out, I should have used clrClass instead of comClass. I made mistakes configuring the clrClass. For instance, I used the same name for "name" that I used for "progId", but the "name" in a clrClass is the full namespace + class name.
Related
I upgraded an OCX library from VS2010/Win7 to VS2019/Win10. The project builds, however when I try and use RegSvr32.exe from an elevated command prompt, I receive error 0x0040200. I did a bit of debugging and the offending call is the call to AfxOleRegisterTypeLib.
Yes, I saw this SO article, which states that "absence of a tlb file near the dll". Other searches state to run from an administrative command prompt.
I do NOT have a TLB near the OCX control. If I try and create one using tlbexp.exe, I get the following error:
TlbExp : error TX0000 : Could not load file or assembly 'file:///C:\pathto.ocx' or one of its dependencies. The module was expected to contain an assembly manifest.
TlbExp command line (used Run as Administrator for all cmd.exe):
"C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools\x64\tlbexp.exe" /VERBOSE "<path to OCX file>" /out:"<path to .tlb output file>"
I downloaded Resource Tuner and that shows the manifest nicely. The manifest does not have any TLB information.
I am thinking that maybe the OCX manifest needs something more that helps TlbExp get at the information that it wants, just a thought.
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="DriveOps.ocx"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
I did use Depends64 (aka Dependency Walker 64-bit) and there are no missing components DLLs. It finds all of them nicely, as does RegSvr32.exe.
Placing the OCX file in C:\Windows\System32 does not help.
To anyone looking at the DLLs, these same DLLs work fine on the Win7 box. Here is some more information on the non-Windows DLLs
PlxApi720_x64.dll: PLX v7.2 API (The Broadcom PLX chip is a PCIe switch (think USB/network switch, just w/PCIe lanes)
LSIDirectAccess.dll: The LSI API is a self-contained DLL that allows the software to talk to the LSI HBA RAID adapter
Ipp*.dll: The Ipp prefix are the DLLs used by the Intel Code Composer Studio redistribution (x64) files, here version 2011, an older one that needs to be updated to the latest and greatest, not to mention now free API. These are all in the System32 folder.
Here is the code:
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB); // <- failure line, through debugging
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
The Intel Code Composer Studio 2011 files are in the C:\Windows\System32 directory, just like on the Win7 box.
For what it is worth, TlbExp fails on the Win7 box too, just it registers, which is probably why the UI can add the control. As I recall, I once replaced the OCX on the Win7 project and VS2010 automatically created the TLB and prefixed Ax in front, but that was a couple of years ago, so my memory may not be the most accurate. Attempting to add the OCX to the UI (.Net WinForms) fails miserably and just says could not be added.
The OCX does use the latest platform tool set (Visual Studio 2019 (v142)).
A comment for developer newbies, regasm.exe is for .Net Assemblies. RegSvr32.exe is for ActiveX Controls (OCX/DLL), which is what I have. RegSvr32 is for dynamically loaded modules, hence the DllRegister entry point.
Thoughts?
Notes From Further Testing
(Saturday 9/21/2019) When I upgraded, I created an empty C++ DLL project and then added all the files, changing the target extension to OCX going through the old project settings and when reasonable aligning them to the new project file wanting to keep things the same. I wanted to do a test and see what happens with a brand new OCX project. I saw that there was such a thing as "MFC ActiveX Control" for a project type in VS2019. I created that and saw that I got different base files, but more importantly RegSvr32.exe works. That means that either the mistake was the initial project file, so I need to import to a clean project or import piece by piece, if that is possible, and see where things break.
(Saturday 9/21/2019) The new test project did not come with a manifest file and TlbExp.exe failed with the same error message like my real project. I went to add new item and saw "Package Manifest". That manifest file, though still produces the same TlbExp.exe error, looks quite different from the application manifest file from above. I created yet another new MFC ActiveX Control project and added in the manifest from above just changing names and saw that the project refused to build throwing 1) Error c1010001 Values of attribute "level" not equal in different manifest snippets. and 2) LNK1327 failure during running mt.exe. That tells me that the original Win7 project and my Win10 project files probably have some error in it, otherwise VS should have thrown these errors to me. That does not answer why even on the test project TlbExp.exe fails. Maybe some attributes in the manifest are required. I just left the defaults.
Package Manifest
(It is the first time that I ever saw one of these. I always saw the app.manifest kind.)
<?xml version="1.0" encoding="utf-8"?>
<!-- TODO: Make sure to set the Package attributes -->
<Package xmlns="urn:Microsoft.WindowsPhone/PackageSchema.v8.00"
Owner=""
OwnerType="OEM"
Platform=""
Component=""
SubComponent="Package"
ReleaseType="Test" >
<Components>
<Driver InfSource="$(_RELEASEDIR)$(TARGETNAME).inf">
<Reference Source="$(_RELEASEDIR)$(TARGETNAME)$(TARGETEXT)" />
<Files>
<!-- For kernel mode drivers, $(DRIVER_DEST) evaluates to "drivers" by default -->
<!-- For user mode drivers, $(DRIVER_DEST) evaluates to "drivers\umdf" by default -->
<File Source="$(_RELEASEDIR)$(TARGETNAME)$(TARGETEXT)" DestinationDir="$(runtime.system32)\$(DRIVER_DEST)" />
</Files>
</Driver>
</Components>
</Package>
This article has an interesting approach, namely create a C++ DLL and then call LoadLibrary(dll) and after that GetProcAddress(module, "DllRegisterServer") to see which one fails. Well, in my case the both functions succeed. That means that the author missed one other failure branch and these two API calls are not the only thing that RegSvr32.exe does.
Though I am still not at the end of the road, as I have aximp.exe / tlbimp.exe issues on the OCX, I found the problem that prevented me from registering the ActiveX control, which was the question here.
The answer is the GUID in the main CPP file:
(I am giving my research, as I could not find anyone explaining how RegSvr32.exe works and what it does. I wanted to share in hopes that it helps others.)
const GUID CDECL _tlid = { 0xFE5C7D88,0xD53C,0x4977,{0xBA,0x56,0x4B,0xF3,0x02,0x0A,0x5D,0x8A} };
which gets used in the main registration function STDAPI DllRegisterServer(void) must match the GUID present in the IDL:
[uuid(FE5C7D88-D53C-4977-BA56-4BF3020A5D8A), version(1.0),
helpfile("DriveOps.hlp"),
helpstring("DriveOps ActiveX Control module"),
control]
library DriveOpsLib
{
...
}
I had 2 different values, hence the failure.
Here is the methodology and research that I used to find the problem, but first I will state the registration function, as that is key again.
STDAPI DllRegisterServer(void)
{
AFX_MANAGE_STATE(_afxModuleAddrThis);
HINSTANCE hiTypeLib = AfxGetInstanceHandle();
if (!AfxOleRegisterTypeLib(hiTypeLib, _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
return NOERROR;
}
The failure was at this line, as I believe was mentioned in the question.
if (!AfxOleRegisterTypeLib(hiTypeLib, _tlid))
I had already found the source code for RegSvr32.exe on the internet. It was part of Microsoft GitHub sources located in VCSamples-master.
Direct Link to RegSvr32.exe: here
Direct Link to download zip: here
The code was a sort of dead end, as it told me what should have been obvious, namely that utility called the DllRegisterServer entry point of a DLL to do all the work. I should have known that, but, well, I had to see it to make sense.
Using procmon.exe, did not shed any light and the various calls to the registry was like reading a foreign language, not helpful.
Here I drew a blank until it occurred to me to get the source code for AfxOleRegisterTypeLib, as that what was failing. I wanted to see what the heck that thing did and what was at line 113 of source file ctlreg.cpp.
I was still thinking on the comment of procmon and a registry issue, but I figured that the code will tell me which one. It took me a bit of research, but I found the code. I love Microsoft sharing code. Their error messages are not helpful, but being able to actually see what they were trying to do so totally helps.
Here is the code:
BOOL AFXAPI AfxOleRegisterTypeLib(HINSTANCE hInstance, REFGUID tlid,
LPCTSTR pszFileName, LPCTSTR pszHelpDir)
{
USES_CONVERSION;
BOOL bSuccess = FALSE;
CString strPathName;
TCHAR *szPathName = strPathName.GetBuffer(_MAX_PATH);
::GetModuleFileName(hInstance, szPathName, _MAX_PATH);
strPathName.ReleaseBuffer();
LPTYPELIB ptlib = NULL;
// If a filename was specified, replace final component of path with it.
if (pszFileName != NULL)
{
int iBackslash = strPathName.ReverseFind('\\');
if (iBackslash != -1)
strPathName = strPathName.Left(iBackslash+1);
strPathName += pszFileName;
}
if (SUCCEEDED(LoadTypeLib(T2COLE(strPathName), &ptlib)))
{
ASSERT_POINTER(ptlib, ITypeLib);
LPTLIBATTR pAttr;
GUID tlidActual = GUID_NULL;
if (SUCCEEDED(ptlib->GetLibAttr(&pAttr)))
{
ASSERT_POINTER(pAttr, TLIBATTR);
tlidActual = pAttr->guid;
ptlib->ReleaseTLibAttr(pAttr);
}
// Check that the guid of the loaded type library matches
// the tlid parameter.
ASSERT(IsEqualGUID(tlid, tlidActual));
if (IsEqualGUID(tlid, tlidActual))
{
// Register the type library.
if (SUCCEEDED(RegisterTypeLib(ptlib, T2OLE((LPTSTR)(LPCTSTR)strPathName), T2OLE((LPTSTR)pszHelpDir))))
bSuccess = TRUE;
}
RELEASE(ptlib);
}
else
{
TRACE1("Warning: Could not load type library from %s\n", (LPCTSTR)strPathName);
}
return bSuccess;
}
I kept receiving an ASSERT, so although line 113 did was on a non-code line, the actual failure was obvious. I knew that I did not fail out on the ASSERT_POINTER, as that error message is different, which meant that I failed at:
ASSERT(IsEqualGUID(tlid, tlidActual));
I looked at the code in detail as well as the entry arguments. I decided to copy and paste this function contents into the real registration code in my OCX to gain further visibility while debugging. I wanted to see the values.
Sure enough, I saw 2 different GUID values, one from the top, my _tlid, and the one returned from the instance handle. I took out my handy-dandy TextPad text editor, though Visual Studio has a Find in Files, but TextPad is so much easier to use. That led to one other instance in the entire solution, namely in DriveOps.idl. That file up until that moment meant nothing to me, but suddenly I saw that the GUID here was the one that RegSvr32.exe pulled from the instance handle.
I unified the IDs, rebuilt, and now RegSvr32.exe no longer complains. Yeah, since I got the code, it had no choice but to register. That it does not modify the registry is a different story and problem from what I can tell, but that is another question. RegSvr32.exe now registers without complaint.
(Yes, I still have tlbimp.exe, aximp.exe, and adding my OCX project to my WinForms project problems, but I got this thing licked and learned something in the process. I guess the difference in line numbers may be some changes Microsoft made in the header, either way, functionality appears the same.)
Great. Issue in all such cases is the IDL has a different GUID as compared to what the DLL / OCX has in code for registration. How it changed, I did not investigate but was able to fix this issue by reading new GUID from project generated *.idl file.
Suppose I'm writing a multi-purpose dll which includes a function for getting the OS version:
void get_os_version(DWORD *major, DWORD *minor)
{
OSVERSIONINFOEX osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOsVersionInfoSize = sizeof(OSVERSIONINFOEX);
// deprecated but easier to use for this example's sake
GetVersionEx((OSVERSIONINFO*)&osvi);
*major = osvi.dwMajorVersion;
*minor = osvi.dwMinorVersion;
}
For the Windows version to be retrieved correctly for versions higher than Windows 8, it is required to embed a manifest that specifies the supported platforms (see details here).
So I disable automatic generation of a manifest for my dll file using the /MANIFEST:NO flag when compiling, and instead add the following manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>
, using the mt tool:
mt -manifest GetOsVersion.dll.manifest -outputresource:GetOsVersion.dll;#2
All good and no errors. Now to use the dll, I create a simple App.exe which loads the dll and calls its function:
int _tmain(int argc, _TCHAR* argv[])
{
DWORD major, minor;
get_os_version(&major, &minor);
printf("%d.%d\n", major, minor);
return 0;
}
But when running App.exe on Windows 10, surprise surprise, the output is:
6.2
, which is the version for Windows 8. If I apply the manifest to the App.exe too:
mt -manifest GetOsVersion.dll.manifest -outputresource:App.exe;#1
, the output is the expected one:
10.0
Why is this happening? And can I solve this problem without adding a manifest to the executable?
I don't have control over the applications that will use my library, but I still want to correctly retrieve the OS version.
An alternative method for determining the actual operating system version is documented on the MSDN page "Getting the System Version":
To obtain the full version number for the operating system, call the GetFileVersionInfo function on one of the system DLLs, such as Kernel32.dll, then call VerQueryValue to obtain the \\StringFileInfo\\<lang><codepage>\\ProductVersion subblock of the file version information.
This will work from a DLL regardless of whether the application has a manifest.
(Of course, there is a reason that GetVersionInfo and friends don't return the actual operating system version: programmers have a nasty tendency to misuse this information. You should seriously consider whether or not providing such a function in your DLL is really a good idea.)
Complementing the accepted answer, here is some starter code for anyone else who wants to implement it:
#pragma comment(lib, "version")
static void print_version()
{
DWORD buffer_size = GetFileVersionInfoSize(_T("kernel32.dll"), NULL);
if (buffer_size == 0)
{
// get error from GetLastError()
return;
}
VOID *buffer = malloc(buffer_size);
if (buffer == NULL)
{
// out of memory
return;
}
if (!GetFileVersionInfo(_T("kernel32.dll"), 0, buffer_size, buffer))
{
goto error;
}
VS_FIXEDFILEINFO *version = NULL;
UINT version_len = 0;
if (!VerQueryValue(buffer,
_T("\\"),
(LPVOID*)&version,
&version_len))
{
goto error;
}
_tprintf(_T("Version is: %u.%u\n"),
HIWORD(version->dwProductVersionMS),
LOWORD(version->dwProductVersionMS));
error:
free(buffer);
}
And the output on Windows 10 is:
Version is 10.0
App (executable) manifest MSDN page describes this matter rather explicitly:
The compatibility section of the app (executable) manifest introduced in Windows helps the operating system determine the versions of Windows an app was designed to target.
Compatibility (and other application settings, such as DPI awareness) are completely ignored if manifest is not an executable manifest. This makes sense because otherwise there would be possible manifest conflicts occurring between manifests in different dlls.
Most of the nodes in a manifest applies to the whole process and is only read from the main .exe module:
The compatibility section of the app (executable) manifest introduced in Windows helps the operating system determine the versions of Windows an app was designed to target.
You should use GetProcAddress and CoCreateInstance to check if the feature you need is present, not the Windows version.
With a little work, GetProcAddress can also be used to figure out what version you are on if you really need that information. Look at the minimum OS version of various kernel32 and user32 functions on MSDN...
I am using MFC with VS2005 and I want to add the shield icon to a button. I created a control member variable for the button and in InitDialog I have
// BCM_SETSHIELD
this->m_ctrlStartact.SendMessage(0x1600+0x000C, 0, TRUE);
this->m_ctrlStartact.SetButtonStyle(BS_FLAT);
However, the shield does not appear. According to the Manifest, I have the correct version of the commctrl:
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
What can be the remaining problem?
SOLVED!!! For some reason I had the manifest file excluded from the build. Now it works :) :) – divB Jul 5 at 15:07
I get this error when i use multiple dataCacheClients. Ive seen this question and this msdn question but at the time of AppFabric 1.0, multiple dataCacheClients were not possible. Microsoft added this feature in AppFabric 1.1 (see changelog), which I'm using currently. Any ideas on why I get this error? Here's my config file:
<configuration>
<configSections>
<section name="dataCacheClients"
type="Microsoft.ApplicationServer.Caching.DataCacheClientsSection, Microsoft.ApplicationServer.Caching.Core"
allowLocation="true"
allowDefinition="Everywhere"/>
</configSections>
<dataCacheClients>
<!--client 1 for caching-->
<dataCacheClient name="dataCacheClient1">
<localCache isEnabled="false" sync="NotificationBased" objectCount="100000"/>
<clientNotification pollInterval="5"/>
<hosts>
<host name="!2345623ghf1.fg.com" cachePort="22233"/>
</hosts>
<securityProperties mode="None" protectionLevel="None" />
<transportProperties maxBufferPoolSize="2147483647" maxBufferSize="2147483647" channelInitializationTimeout="60000" receiveTimeout="900000"/>
</dataCacheClient>
<!-- client 2 for session -->
<dataCacheClient name="dataCacheClient2">
<localCache isEnabled="false" sync="NotificationBased" objectCount="100000"/>
<clientNotification pollInterval="5"/>
<hosts>
<host name="!2345623ghf2.fg.com" cachePort="22233"/>
</hosts>
<securityProperties mode="None" protectionLevel="None" />
<transportProperties maxBufferPoolSize="2147483647" maxBufferSize="2147483647" channelInitializationTimeout="60000" receiveTimeout="900000"/>
</dataCacheClient>
</dataCacheClients>
<system.web>
<compilation debug="true" targetFramework="4.0">
</compilation>
<sessionState
mode="Custom"
customProvider="AppFabricCacheSessionStoreProvider">
<providers>
<add name="AppFabricCacheSessionStoreProvider"
type="Microsoft.Web.DistributedCache.DistributedCacheSessionStateStoreProvider, Microsoft.Web.DistributedCache"
cacheName="default"
dataCacheClientName="dataCacheClient2" />
</providers>
</sessionState>
NOTE:
I'm using the DLL's found in .\Program Files\AppFabric 1.1 for Windows Server
More Error details :
I was finally able to get it working. There were some rudimentary but stupid mistakes I committed. Hopefully someone with the same issues would be able to get some guidance on this by my answer. The mistakes I committed/how it was rectified :
1) Check the DLL's CLR version
Always, I mean, always check the version of the DLLs you're using to refer in your consuming client. The DLLs to look out for are :
Microsoft.ApplicationServer.Caching.Core.dll
Microsoft.ApplicationServer.Caching.Client.dll
Microsoft.WindowsFabric.Common.dll
Microsoft.WindowsFabric.Data.Common.dll
Microsoft.Web.DistributedCache (this was what was causing me problems - I had an older version added in my solution; there's no need to refer this, just having this DLL in the same folder as the Caching.Core and Caching.Client is enough)
A good (or rather fail-proof) way to get the latest DLLs is to download & install Appfabric and get the DLLs from .\Program Files\AppFabric 1.1, add it in a folder inside your project and refer it from there.
2) DataCacheFactory must have a reference to what dataCacheClient its referring to
Just like how AppFabricCacheSessionStoreProvider must contain a dataCacheClientName attribute to refer to a specific cluster put in dataCacheClient, DataCacheFactory init in code must also contain a reference to the dataCacheClient which is gonna take care of caching :
DataCacheFactory _factory = new DataCacheFactory(new DataCacheFactoryConfiguration("dataCacheClient1"))
Thanks to everyone who helped in solving this issue!
I had this problem on one of our development machines and it was ultimately found to be installation of Windows Server AppFabric. My configuration was totally correct. The same configuration worked on all machines except one and once we un-installed Windows Server AppFabric from that machine and installed Microsoft AppFabric 1.1 version, the issue was resolved.
I'm also using AppFabric to store Asp.NET SessionState.
Can you use CMFCVisualManager with a dialog based application to change the applications appearance? If so how is it done?
The idea is to change the shape, colour etc. of controls such as push buttons using the MFC Feature Pack released with MSVC 2008.
No, can't be done, at least not if you're talking about the Feature Pack version. Version 10 of the BCGSoft libraries do have this functionality, see for example: http://www.bcgsoft.com/bcgcontrolbarpro-versions.htm and http://www.bcgsoft.com/images/SkinnedBuiltInDlgs.jpg. The MFC feature pack is more or less the previous version of the BCGSoft libraries, MS bought a license from them.
You need to add the Common Controls manifest to your project resources. Here is the code for the manifest file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="X86"
name="Program Name"
type="win32"
/>
<description>Description of Program</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>
I think you can have some MFC-feature-pack features by implementing OnApplicationLook on your base CDialog (check Step 4 on this page). It might be better to implement the whole OnApplicationLook method, but you can test your application simply by adding this to OnInitDialog:
CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerOffice2007::Office2007_Silver);
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerOffice2007));
CDockingManager::SetDockingMode(DT_SMART);
RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW | RDW_FRAME | RDW_ERASE);
This is the least amount of code to enable the Visual Styles. You should be able to pop your CDialog into the frame easily. The IDR_MAINFRAME is a menu resource.
class CMFCApplication2Dlg : public CFrameWndEx
{
CMFCMenuBar bar;
public:
CMFCApplication2Dlg() : CFrameWndEx()
{
LoadFrame(IDR_MAINFRAME);
bar.Create(this);
}
};
class CMFCApplication2App : public CWinAppEx
{
public:
virtual BOOL InitInstance()
{
CWinAppEx::InitInstance();
CMFCVisualManagerOffice2007::SetStyle(
CMFCVisualManagerOffice2007::Office2007_ObsidianBlack);
CMFCVisualManager::SetDefaultManager(
RUNTIME_CLASS(CMFCVisualManagerOffice2007));
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
m_pMainWnd = new CMFCApplication2Dlg();
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
}
};
CMFCApplication2App theApp;