PlatformNotSupportedException when calling a Web Service method - web-services

Ok, I'm really stumped with this one. I have this Compact Framework application which calls your standard .NET web service. This has been working pretty well for a while, but recently we were asked to make this software work on another Windows CE device.
This new device seems to have been manufactured in Korea, and has some weird/buggy default configuration. Regional settings on the Control Panel show that the locale is set to English(United States) and the User Interface Language and Input Language settings have this value set as well.
There are some weird issues though. On Windows Explorer, the usual '\' characters that are used to separate folders, appear as a crossed-out W. The small input panel has some characters that are also wrong, some look clearly Korean.
The problem with all of this, is that for some reason I get a PlatformNotSupportedException, when calling a Web Service method that returns a DataSet. On the debugger I can see that the the CurrentUICulture is properly set to 'en-US', but somehow this doesn't keep the program from running into this issue.
I think that the Korean language installed on the device is conflicting with the culture configuration of the Web Service, but I don't have a clue about the details, and I don't know how I could fix it. Any help would be greatly appreciated. Thanks.
This is the full stack trace:
System.PlatformNotSupportedException - at System.Globalization.CultureInfo..ctor(String name, Boolean useUserOverride)
at System.Globalization.CultureInfo..ctor(String name)
at System.Data.XSDSchema.HandleDataSet(XmlSchemaElement node, Boolean isNewDataSet)
at System.Data.XSDSchema.LoadSchema(XmlSchemaSet schemaSet, DataSet ds)
at System.Data.DataSet.ReadXSDSchema(XmlReader reader, Boolean denyResolving)
at System.Data.DataSet.ReadXml(XmlReader reader, XmlReadMode mode, Boolean denyResolving)
at System.Data.DataSet.ReadXmlSerializable(XmlReader reader)
at System.Data.DataSet.System.Xml.Serialization.IXmlSerializable.ReadXml(XmlReader reader)
at System.Xml.Serialization.XmlSerializationReader.DeserializeSerializableElement(LogicalType deserializeAs, Accessor accessor, Fixup fixup, Object fixupTarget, String identifier, Boolean emptyValue, Boolean nullValue)
at System.Xml.Serialization.XmlSerializationReader.deserializeElement(Accessor accessor, Fixup fixup, Object fixupTarget)
at System.Xml.Serialization.XmlSerializationReader.DeserializeElementMember(MemberValueCollection members, Object fixupTarget, Hashtable internalState, Boolean& firstElement)
at System.Xml.Serialization.XmlSerializationReader.deserializeMembers(MemberValueCollection members, Object fixupTarget)
at System.Xml.Serialization.XmlSerializationReader.DeserializeComplexElement(LogicalType deserializeAs, Accessor accessor, Fixup fixup, Object fixupTarget, String identifier, Boolean emptyValue, Boolean nullValue)
at System.Xml.Serialization.XmlSerializationReader.deserializeElement(Accessor accessor, Fixup fixup, Object fixupTarget)
at System.Xml.Serialization.XmlSerializationReader.DeserializeElementMember(MemberValueCollection members, Object fixupTarget, Hashtable internalState, Boolean& firstElement)
at System.Xml.Serialization.XmlSerializationReader.deserializeMembers(MemberValueCollection members, Object fixupTarget)
at System.Web.Services.Protocols.SoapMessageParser.execute()
at System.Web.Services.Protocols.SoapMessageSerializer.Deserialize(XmlReader reader, SoapHttpClientProtocol client, LogicalSoapMethod soapMethod, Boolean soap12)
at System.Web.Services.Protocols.SoapHttpClientProtocol.doInvoke(String methodName, Object[] parameters, WebClientAsyncResult asyncResult)

The culture you're trying to use is not a neutral culture and the underlying Win32 locale is not supported by the device's OS. In any case, for a web service, wouldn't you want to use the invariant culture?
EDIT: The schema for the DataSet needs to specify a culture by way of Microsoft schema extension. Try adding the namespace declaration
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
to your schema, and the attribute
msdata:Locale=""
to the xs:element that represents the root of the DataSet, to force the use of the invariant culture; a non-empty string value will be passed to the CultureInfo(string) constructor. Otherwise, if the attribute
msdata:UseCurrentLocale="true"
is present, whatever the device's current locale is will be used. If neither attribute is present, it's hardcoded to LCID 0x0409, which is US English.

You either need to change the target platform to X64 or X32 from your CSproj properties build settings or just simply turn off the said System.PlatformNotSupportedException from exception settings under debug windows option.

Related

(C++ WinForms VS 2022) Icon Exception

When I attempt to change the icon of the form in the properties window (this), this line of code gets generated in the .h file:
this->Icon = (cli::safe_cast<System::Drawing::Icon^>(resources->GetObject(L"$this.Icon")));
But when I try to run it, it gives me a System.Resources.MissingManfiestResourceException error:
System.Resources.MissingManifestResourceException HResult=0x80131532
Message=Could not find any resources appropriate for the specified
culture or the neutral culture. Make sure
"Thermodynamics_Generator.Form1.resources" was correctly embedded or
linked into assembly "thermodynamics_generator" at compile time, or
that all the satellite assemblies required are loadable and fully
signed. Source=mscorlib StackTrace: at
System.Resources.ManifestBasedResourceGroveler.HandleResourceStreamMissing(String
fileName) at
System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(CultureInfo
culture, Dictionary`2 localResourceSets, Boolean tryParents, Boolean
createIfNotExists, StackCrawlMark& stackMark) at
System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo
requestedCulture, Boolean createIfNotExists, Boolean tryParents,
StackCrawlMark& stackMark) at
System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo
culture, Boolean createIfNotExists, Boolean tryParents) at
System.Resources.ResourceManager.GetObject(String name, CultureInfo
culture, Boolean wrapUnmanagedMemStream) at
System.Resources.ResourceManager.GetObject(String name) at
Thermodynamics_Generator.Form1.InitializeComponent() in
C:\Users\my_name\source\repos\thermodynamics_generator\thermodynamics_generator\thermodynamics_generator.h:line
1194 at Thermodynamics_Generator.Form1..ctor() in
C:\Users\my_name\source\repos\thermodynamics_generator\thermodynamics_generator\thermodynamics_generator.h:line
26 at main() in
C:\Users\my_name\source\repos\thermodynamics_generator\thermodynamics_generator\CppCLR_WinformsProject.cpp:line
11
And I have tried something like this from another post to do this instead:
this->Icon = gcnew System::Drawing::Icon(L"app.ico");
It works, but when ran on other computers, it just does not want to run at all (only wants to run on my computer).
I also checked the .resx file to see $this.Icon is there but still gives me an exception.
If there is other things I mention, let me know.
this->Icon = (cli::safe_cast<System::Drawing::Icon^>(resources->GetObject(L"$this.Icon")));
This line of code is automatically generated, where $this.Icon contains the file path, you could read the documentation for the GetObject(). And the documentation states that
If the appropriate resources cannot be found, the constructor call
creates a valid ResourceManager object. However, the attempt to
retrieve a resource throws a MissingManifestResourceException
exception. For information about dealing with the exception, see the
Handling MissingManifestResourceException and MissingSatelliteAssembly
Exceptions section later in this article.
We could conclude that the program did not find your resource file. If you want to run the program on other computers, you must ensure that the icon path is consistent with your computer.
Edit:
I suggest you to check if the resource is included as a project, select All Files in Solution Exploer, then right click on the resource file and select Include In Project.

Getting ColdFusion-Called Web Service to Work with JavaLoader-Loaded Objects

Is it possible to use JavaLoader to get objects returned by CF-called web services, and JavaLoader-loaded objects to be the same classpath context? I mean, without a lot of difficulty?
// get a web service
ws = createObject("webservice", local.lms.wsurl);
// user created by coldfusion
user = ws.GenerateUserObject();
/* user status created by java loader.
** this api provider requires that you move the stubs
** (generated when hitting the wsdl from CF for the first time)
** to the classpath.
** this is one of the stubs/classes that gets called from that.
*/
UserStatus = javaLoader.create("com.geolearning.geonext.webservices.Status");
// set user status: classpath context clash
user.setStatus(UserStatus.Active);
Error:
Detail: Either there are no methods with the specified method name and
argument types or the setStatus method is overloaded with argument
types that ColdFusion cannot decipher reliably. ColdFusion found 0
methods that match the provided arguments. If this is a Java object
and you verified that the method exists, use the javacast function to
reduce ambiguity.
Message: The setStatus method was not found.
MethodName setStatus
Even though the call, on the surface, matches a method signature on user--setStatus(com.geolearning.geonext.webservices.Status)--the class is on a different classpath context. That's why I get the error above.
Jamie and I worked on this off-line and came up with a creative solution :)
(Apologies for the long answer, but I thought a bit of an explanation was warranted for those who find class loaders as confusing as I do. If you are not interested in the "why" aspect, feel free to jump to the end).
Issue:
The problem is definitely due to multiple class loaders/paths. Apparently CF web services use a dynamic URLClassLoader (just like the JavaLoader). That is how it can load the generated web service classes on-the-fly, even though those classes are not in the core CF "class path".
(Based on my limited understanding...) Class loaders follow a hierarchy. When multiple class loaders are involved, they must observe certain rules or they will not play well together. One of the rules is that child class loaders can only "see" objects loaded by an ancestor (parent, grandparent, etcetera). They cannot see classes loaded by a sibling.
If you examine the object created by the JavaLoader, and the other by createObject, they are indeed siblings ie both children of the CF bootstrap class loader. So the one will not recognize objects loaded by the other, which would explain why the setStatus call failed.
Given that a child can see objects loaded by a parent, the obvious solution is to change how the objects are constructed. Structure the calls so that one of the class loaders ends up as a parent of the other. Curiously that turned out to be trickier than it sounded. I could not find a way to make that happen, despite trying a number of combinations (including using the switchThreadContextClassLoader method).
Solution:
Finally I had a crazy thought: do not load any jars. Just use the web service's loader as the parentClassLoader. It already has everything it needs in its own individual "class path":
// display class path of web service class loader
dynamicLoader = webService.getClass().getClassLoader();
dynamicClassPath = dynamicLoader.getURLS();
WriteDump("CLASS PATH: "& dynamicClassPath[1].toString() );
The JavaLoader will automatically delegate calls for classes it cannot find to parentClassLoader - and bingo - everything works. No more more class loader conflict.
webService = createObject("webservice", webserviceURL, webserviceArgs);
javaLoader = createObject("component", "javaloader.JavaLoader").init(
loadPaths = [] // nothing
, parentClassLoader=webService.getClass().getClassLoader()
);
user = webService.GenerateUserObject();
userStatus = javaLoader.create("com.geolearning.geonext.webservices.Status");
user.setStatus(userStatus.Active);
WriteDump(var=user.getStatus(), label="SUCCESS: user.getStatus()");

Coldfusion 8 - mapping conflict causes "argument is not of interface type" error

I have been researching this, and cannot seem to find anything about it.
We work on CF8. When my coworker tried installing my latest code updates, he started seeing errors that the argument supplied to a function was not of the specified interface type. Worked fine for me. Same set up. Sometimes it works for him. Also have the problem on our dev server.
I have since been able to isolate and reproduce the problem locally.
Here is the set up.
I have 2 mappings on the server:
"webapp/" goes to c:\webroot\
"packages/" goes to c:\webroot\[domain]
Then I created an interface, call it ISubject and a component that implements it, called Person, and saved both under packages. Here is the declaration for Person:
cfcomponent implements="packages.ISubject"
Finally, there is a component, called SubjectMediator with a function, called setSubject, that wants an object of the ISubject interface type. Here is the argument declaration for setSubject:
cfargument name="subject_object" type="packages.ISubject"
To implement:
variables.person = createObject("component", "packages.Person").Init();
variables.subjectMediator = createObject("component", "packages.SubjectMediator ").Init();
variables.subjectMediator.setSubject(variables.person);
That last line throws the error that Person is not of type ISubject. If I do isInstanceOf() on Person against ISubject it validates fine.
So the reason this is happening? Dumping getMetaData(variables.person) shows me that the interface path is webapp.[domain].ISubject. And indeed, if I change the type attribute of the argument to use this path instead of packages.ISubject, all is fine again.
Coldfusion seems to be arbitrarily choosing which mapping to resolve the interface to, and then simply doing a string comparison for check the type argument?
Anyone had to contend with this? I need the webapp mapping, and I cannot change all references to "packages" to "webapp.[domain]." I also am not able in this instance to use an application-specific mapping for webapp. While any of these 3 options would circumvent the issue, I'm hoping someone has some insight...
The best I've got is to set argument type to "any" and then check isInstanceOf() inside the function... Seems like poor form.
Thanks,
Jen
Can you move the contents of the packages mapping to outside the webroot? This seems like the easiest way to fix it.

Writing a simple ActiveX control for IE that has one method

I'm learning how to write a scriptable ActiveX control. My goal is to have a tiny control that can check to see if something is installed on the system. What I've done so far is:
Create a MFC ActiveX control project in VS2008
Add some 'safe for scripting' bits that I found here.
Extend the IDL to provide my "IsInstalled" method, which for now returns TRUE unconditionally (but will later read some keys from the registry.)
Build the control and run regsvr32 on it. I verified that it does show up in HKEY_CLASSES_ROOT, and when I instantiate the object, the IE Developer Tools "Locals" pane shows that the object is of type _D[my plugin name]. Not only that, but my IsInstalled() method shows up underneath that object.
However, when I call IsInstalled(), I just can't get it to work:
JScript Debugger - Breaking on JScript runtime error -(n http://img138.imageshack.us/img138/1586/whycomwhy.png
I'm at a loss. I've also tried making IsInstalled a property instead of a method, using VARIANT_BOOL instead of boolean instead of BOOL in the IDL, you name it.
Here's the relevant excerpts of code.
The header:
afx_msg VARIANT_BOOL IsInstalled();
The implementation:
afx_msg VARIANT_BOOL
CMyAXCtrl::IsInstalled()
{
return TRUE;
}
The dispatch map:
BEGIN_DISPATCH_MAP(CMyAXCtrl, COleControl)
DISP_FUNCTION_ID(CMyAXCtrl, "IsInstalled", dispidIsInstalled, IsInstalled, VT_BOOL, VTS_NONE)
END_DISPATCH_MAP()
The dispatch part of the IDL:
[ uuid(6B662202-CF13-4144-AA33-C3FEE9C2C962),
helpstring("Dispatch interface for My Control")]
dispinterface _Daxplugin
{
properties:
methods:
[id(1)] VARIANT_BOOL IsInstalled();
};
If there's any other relevant bits of code I should provide, let me know. But I'm stumped here. Thank you in advance!
You almost certainly have the wrong prototype for a scriptable function. OLE Automation for scripting languages tends to rely on returning a HRESULT then using an out parameter for the actual return code.
So change it to
[id(1)] HRESULT IsInstalled(VARIANT_BOOL* p);
Also TRUE != VARIANT_TRUE, you must return VARIANT_TRUE which is equal to -1 instead of 1.
Hope some of that actually helps, but without the actual error I might be mistaken :)
You could mark your control as save for scripting by implementing IObjectSafety or by marking the Object as save while registering it (as supposed by the link you provided).
Have you run regsvr32 after adding the code to mark it save for scripting?
You can check the registry if your control has the safe for scripting bits set.
If the bits are set you will find the two keys {7DD95802-9882-11CF-9FA9-00AA006C42C4} (Safe for Initialization)
{7DD95801-9882-11CF-9FA9-00AA006C42C4}(Safe For Scripting) as subkeys of ImplementedCategories in your object.
I would suggest to implement IObjectSafety since it doesn't depend on your class to register itself.

Create registry entry to associate file extension with application in C++

I would like to know the cleanest way of registering a file extension with my C++ application so that when a data file associated with my program is double clicked, the application is opened and the filename is passed as a parameter to the application.
Currently, I do this through my wix installer, but there are some instances where the application will not be installed on ths user's computer, so I also need the option of creating the registry key through the application.
Additionally, will this also mean that if the application is removed, unused entries in the registry will be left lying around?
Your basic overview of the process is found in this MSDN article. The key parts are at the bottom of the list:
Register the ProgID
A ProgID (essentially, the file type registry key) is what contains your important file type properties, such as icon, description, and context menu items including applications used when the file is double clicked. Many extensions may have the same file type. That mapping is done in the next step:
Register the file name extension for the file type
Here, you set a registry value for your extension, setting that extension's file type to the ProgID you created in the previous step.
The minimum amount of work required to get a file to open with your application is setting/creating two registry keys. In this example .reg file, I create a file type (blergcorp.blergapp.v1) and associate a file extension (.blerg) with it.
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command]
#="c:\path\to\app.exe \"%1\""
[HKEY_CURRENT_USER\Software\Classes\.blerg]
#="blergcorp.blergapp.v1"
Now, you probably want to accomplish this programmatically. To be absolutely kosher, you could check for the existence of these keys, and change your program behavior accordingly, especially if you're assuming control of some common file extension. However, the goal can be accomplished by setting those two keys using the SetValue function.
I'm not positive of the exact C++ syntax, but in C# the syntax looks something like this:
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\blergcorp.blergapp.v1\shell\open\command", null, #"c:\path\to\app.exe \"%1\"");
Registry.SetValue(#"HKEY_CURRENT_USER\Software\Classes\.blerg", null, "blergcorp.blergapp.v1");
Of course you could manually open each sub key, manually create the ProgID and extension subkey, and then set the key value, but a nice thing about the SetValue function is that if the keys or values don't exist, they will automatically be created. Very handy.
Now, a quick word about which hive to use. Many file association examples online, including ones on MSDN, show these keys being set in HKEY_CLASSES_ROOT. I don't recommend doing this. That hive is a merged, virtual view of HKEY_LOCAL_MACHINE\Software\Classes (the system defaults) and HKEY_CURRENT_USER\Software\Classes (the per-user settings), and writes to any subkey in the hive are redirected to the same key in HKEY_LOCAL_MACHINE\Software\Classes. Now, there's no direct problem doing this, but you may run into this issue: If you write to HKCR (redirected to HKLM), and the user has specified the same keys with different values in HKCU, the HKCU values will take precedence. Therefore, your writes will succeed but you won't see any change, because HKEY_CURRENT_USER settings take precedence over HKEY_LOCAL_MACHINE settings.
Therefore, you should take this into consideration when designing your application. Now, on the flip side, you can write to only HKEY_CURRENT_USER, as my examples here show. However, that file association setting will only be loaded for the current user, and if your application has been installed for all users, your application won't launch when that other user opens the file in Windows.
That should be a decent primer for what you want to do. For further reading I suggest
Best Practices for File Association
File Types and File Association, especially
How File Associations Work
And see also my similar answer to a similar question:
Associating file extensions with a program
This is a two step process:
1. Define a program that would take care of extension: (unless you want to use existing one)
1.1 create a key in "HKCU\\Software\\Classes\\" for example
"Software\\Classes\\YourProgramName.file.ext"
1.2 create subkey "Software\\Classes\\YourProgramName.file.ext\\DefaultIcon"
1.2.1 set default value ("") to your application full path to get
icon from resources
1.3 create a subkey "Software\\Classes\\YourProgramName.file.ext\\Shell\\OperationName\\Command"
OperationName = for example Open, Print or Other
1.3.1 set default value ("") to your application full path +optional runtime params (filename)
2.Associate file extension with program.
2.1 create a key HKCU\\Software\\Classes\\.ext - here goes your extension
2.2 set default value to the program definition key
("YourProgramName.file.ext")
Below is part of the program written in c# which associate file extension. It is not c++ but i think it is simple enought to explain itself and AFAIK it is verv simmilar if not identical to the code in c++
1.
RegistryKey keyPFCTExt0 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc", true);
if (keyPFCTExt0 == null)
{
keyPFCTExt0 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc");
keyPFCTExt0.CreateSubKey("DefaultIcon");
RegistryKey keyPFCTExt0ext = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\DefaultIcon", true);
keyPFCTExt0ext.SetValue("", Application.ExecutablePath +",0");
keyPFCTExt0ext.Close();
keyPFCTExt0.CreateSubKey("Shell\\PFCT_Decrypt\\Command");
}
keyPFCTExt0.SetValue("", "PFCT.file.enc");
keyPFCTExt0.Close();
2.
RegistryKey keyPFCTExt1 = Registry.CurrentUser.OpenSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command", true);
if (keyPFCTExt1 == null)
keyPFCTExt1 = Registry.CurrentUser.CreateSubKey("Software\\Classes\\PFCT.file.enc\\Shell\\PFCT_Decrypt\\Command");
keyPFCTExt1.SetValue("", Application.ExecutablePath + " !d %1"); //!d %1 are optional params, here !d string and full file path
keyPFCTExt1.Close();
I don't know why people keep saying that HKEY_CURRENT_USER\Software\Classes\<.ext>'s Default value (which will redirect you into another (software-created) class.
It does work, but it will be overridden by
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\<.ext>\UserChoice
And I believe Microsoft recommends the second practice- because it's what the built-in "open with" is doing. The value of Progid" key is equal to default value of HKEY_CURRENT_USER\Software\Classes\<.ext> in this case.
I found the following while trying to manipulate associations using C#:
hkcu\software\microsoft\windows\currentVersion\explorer\fileexts.reg\userchoice -> for user specific settings. The values in the openWithProgIds
key point to the keys in the hkcr.
hkcr\xfile\shell\open\muiVerb value or hkcr\xfile\shell\open\command\default value -> affects open handler. This is the value that contains the path to a program.
hkcr\ .x -> affects context menu (new x) among other things related to the menus.
I don't know the C++ code, but given these info you must be able to manipulate the registry using the registry API.