I have a strange problem. I have a kiosk application (running as device owner, set by dpm) that is attempting to perform a self upgrade from an apk file that has already been downloaded. The file is downloaded correctly and the upgrade appears to work correctly. The application quits, the system gives a notification that the application has been upgraded by the device owner before the application relaunches.
When the application has relaunched, the version number is reporting as the new version, but none of the modified functionality in the app is present. On the initial login form I added a label with the version number hardcoded into it to compare to the version pulled using Xamarin.Essentials.AppInfo.Version.ToString(). The hardcoded version does not update, but the software version shows correctly.
The device is a Samsung Galaxy Tab A.
I have added a toast on exception which is showing no error messages. I have tried changing the PackageInstallMode to InheritExisting, this didn't seem to make any difference.
The method used for the upgrade is here.
public void UpgradeFromLocalFile(string downloadedFile)
{
try
{
if (MainActivity.Instance.CheckSelfPermission(Manifest.Permission.WriteExternalStorage) == Permission.Denied)
{
MainActivity.Instance.RequestPermissions(new string[] { Manifest.Permission.WriteExternalStorage }, 0);
}
if (MainActivity.Instance.CheckSelfPermission(Manifest.Permission.ReadExternalStorage) == Permission.Denied)
{
MainActivity.Instance.RequestPermissions(new string[] { Manifest.Permission.ReadExternalStorage }, 0);
}
if (MainActivity.Instance.CheckSelfPermission(Manifest.Permission.InstallPackages) == Permission.Denied)
{
MainActivity.Instance.RequestPermissions(new string[] { Manifest.Permission.InstallPackages }, 0);
}
var installer = MainActivity.Instance.PackageManager.PackageInstaller;
var parameters = new PackageInstaller.SessionParams(PackageInstallMode.FullInstall);
parameters.SetAppPackageName("my.package.name");
var sessionid = installer.CreateSession(parameters);
var session = installer.OpenSession(sessionid);
var fis = File.OpenRead(downloadedFile);
using (var outputstream = session.OpenWrite("my.package.name", 0, -1))
{
fis.CopyTo(outputstream);
session.Fsync(outputstream);
outputstream.Close();
outputstream.Dispose();
fis.Close();
fis.Dispose();
GC.Collect();
}
var pendingIntent = PendingIntent.GetBroadcast(MainActivity.Instance, sessionid, new Intent(Intent.ActionInstallPackage), 0);
session.Commit(pendingIntent.IntentSender);
}
catch(Exception ex)
{
Toast.MakeText(MainActivity.Instance.ApplicationContext, string.Format("Update failed, you may not have full device admin privileges. Error - {0}", ex.ToString()), ToastLength.Long).Show();
}
}
I'd expect the software version to change as well as the actual executable version. Does anyone have any clues as to what I'm doing wrong.
Ok, after much stuffing around and inspecting install logs with logcat, it seems the apk I was generating by deploy is incomplete. I had to set up a keystore to sign my app and then create a complete archive.
Right click the android proj -> archive.. -> Distribute -> Ad Hoc
This allowed me to self update properly.
Phew. Was bashing my head against it for days. Hope this saves someone else some time.
Related
I am writing a 64-bit C# Windows forms application that will run under Windows PE 10 64-bit to pull the Display Name from Active Directory. I have to use 64-bit because the PCs I am running this on will only boot UEFI so I cannot boot into a 32-bit recovery environment. Every time my code reaches a certain spot, I receive the error message: Unknown Error [0x80005000]. If I compile this and run in 32-bit Windows PE 10, it runs fine, with no modification to the code other than compiling 32-bit.
I am using VS2019 and the code is using .NET v4.7.
Below is the code that I am using:
using (PrincipalContext ad = new PrincipalContext(ContextType.Domain,
"dotted.domain.com", "OU=Users,DC=dotted,DC=domain,dc=com",
ContextOptions.Negotiate, main.interactiveUser, main.interactivePwd))
{
try
{
//this is where it fails
using (UserPrincipal wantedUser = UserPrincipal.FindByIdentity(ad, combo1.Text))
{
if (wantedUser != null)
{
givenName = wantedUser.DisplayName;
}
else
{
MessageBox.Show("User name not found in AD. Please locate manually",
"Error finding name", MessageBoxButtons.OK, MessageBoxIcon.Error);
givenName = "DisplayNameNotFoundInAD";
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
break;
}
}
Here are the meanings of my variables:
dotted.domain.com = the name of my domain
main.interactiveUser = user name to log into the domain with from another form
main.interactivePwd = password for said user name
combo1.Text = text from combo box that has the user name I want to search for
wantedUser = user name of the person I want the display name for
givenName = display name for the user name I am searching for
I have tried it with and without the OU=Users with the same result. It also works fine if I am running in Windows normally. I found some other posts about possibly editing the registry with owner info, that made no difference.
Any ideas on why this is happening?
Had a similar issue accessing the registry in 64-bit WinPE in the past. From my understanding it is exactly what PrincipalContext does.
In my case, I had to uncheck
prefer 32-bit
on the build-tab in VS.
PS: Would have commented only, but currently I'm not on enough reputation
did someone knows how to do that because i had investigate about, but i found only wrong/don't working answers I had try a lot of solutions but it seems to be wrong, like using the Chilkat directory , using ArchiveTransferManager ...
Chilkat.Rest rest = new Chilkat.Rest();
bool bTls = true;
int port = 443;
bool bAutoReconnect = true;
bool success = rest.Connect("glacier.eu-west-1.amazonaws.com", port, bTls, bAutoReconnect);
Chilkat.AuthAws authAws = new Chilkat.AuthAws();
authAws.AccessKey = ;
authAws.SecretKey = ;
authAws.ServiceName = "glacier";
authAws.Region = "us-west-1";
success = rest.SetAuthAws(authAws);
rest.AddHeader("x-amz-glacier-version", "2012-06-01");
string filePath = "20190422.csv";
Chilkat.Crypt2 crypt = new Chilkat.Crypt2();
crypt.HashAlgorithm = "sha256-tree-hash";
crypt.EncodingMode = "hexlower";
string treeHashHex = crypt.HashFileENC(filePath);
rest.AddHeader("x-amz-sha256-tree-hash", treeHashHex);
crypt.HashAlgorithm = "sha256";
string linearHashHex = crypt.HashFileENC(filePath);
authAws.PrecomputedSha256 = linearHashHex;
rest.AddHeader("x-amz-archive-description", filePath);
Chilkat.Stream fileStream = new Chilkat.Stream();
fileStream.SourceFile = filePath;
string responseStr = rest.FullRequestStream("POST", "/682988997959/vaults/streamqueuesvault", fileStream);
if (rest.LastMethodSuccess != true)
{
Debug.WriteLine(rest.LastErrorText);
return;
}
int respStatusCode = rest.ResponseStatusCode;
if (respStatusCode >= 400)
{
Debug.WriteLine("Response Status Code = " + Convert.ToString(respStatusCode));
Debug.WriteLine("Response Header:");
Debug.WriteLine(rest.ResponseHeader);
Debug.WriteLine("Response Body:");
Debug.WriteLine(responseStr);
return;
}
Debug.WriteLine("response status code = " + Convert.ToString(respStatusCode));
string archiveId = rest.ResponseHdrByName("x-amz-archive-id");
Debug.WriteLine("x-amz-archive-id = " + archiveId);
string location = rest.ResponseHdrByName("Location");
Debug.WriteLine("Location = " + location);
Here is a step by step guide on How to upload a file from my local machine to a vault of s3 glacier using c# in a console app?. First I would like to present some basic background information that will be used later in the solution. Feel free to skip ahead to the solution if you are smart on S3 Glacier.
If you have AWS SDK for .NET and VS already installed, you can download the Repo from Github.
Quick Intro to S3-Glacier
Amazon S3 Glacier is Amazons low cost long term storage service.
In Glacier terminology, an object is referred to as an Archive. Also the folders where you store archives are called Vaults. Its pretty simple - From the Glacier FAQ:
Q: How is data within Amazon S3 Glacier organized?
You store data in Amazon S3 Glacier as an archive. Each archive is assigned a unique archive ID that can later be used to retrieve the data. An archive can represent a single file or you may choose to combine several files to be uploaded as a single archive. You upload archives into vaults. Vaults are collections of archives that you use to organize your data.
When you upload objects to S3 Glacier, the objects don't immediately appear in your Glacier console. Your Glacier console will refresh once a day.
Amazon recommends you use the AWS SDK for .NET when developing C# applications that interface AWS services.
Simple Solution
Before you code, go into your AWS Console and create a S3 Glacier Vault name 'TestVault'.
At the time of this solution (April 2019), I suggest you use Visual Studio 2019. These steps are similar for earlier versions of Visual Studio.
The code I present was taken directly from the AWS SDK for .NET Documentation.
Once your visual studio is ready, then follow these steps:
Create a new project (use template -> Console App (.NET Framework) - not Console App (.NET Core) and name it ConsoleApp9
Add the AWS SDK to your project via NuGet package manager command.
Tools menu, select Nuget Package Manager, and click Package Manager Console.
then type Install-Package AWSSDK.
For a MAC use Project->Add Nuget Packages. Search for "AWSSDK.Glacier" and install it.
Below is the working code. You need to copy most of this into your Program.cs and remove the default "Hello World" code. Your final Program.cs code should look like
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Amazon.Glacier;
using Amazon.Glacier.Transfer;
using Amazon.Runtime;
namespace ConsoleApp9
{
class Program
{
static string vaultName = "TestVault";
static string archiveToUpload = "C:\\Windows\\Temp\\TEST-ARCHIVE.txt";
static void Main(string[] args)
{
try
{
var manager = new ArchiveTransferManager(Amazon.RegionEndpoint.USEast1);
// Upload an archive.
string archiveId = manager.Upload(vaultName, "upload archive test", archiveToUpload).ArchiveId;
Console.WriteLine("Archive ID: (Copy and save this ID for use in other examples.) : {0}", archiveId);
Console.WriteLine("To continue, press Enter");
Console.ReadKey();
}
catch (AmazonGlacierException e) { Console.WriteLine(e.Message); }
catch (AmazonServiceException e) { Console.WriteLine(e.Message); }
catch (Exception e) { Console.WriteLine(e.Message); }
Console.WriteLine("To continue, press Enter");
Console.ReadKey();
}
}
}
Put the file that you want to be uploaded to Glacier as c:\Windows\Temp\Test-Archive.txt. You can put the file anywhere you want, just update the variable archiveToUpload in your code to reflect the location.
If your region is not USEast1, Change the AWS Region on the line just after the try:
var manager = new ArchiveTransferManager(Amazon.RegionEndpoint.YOUR-REGION);
Run the program and it will upload the file. If you have installed the AWS SDK before this will likely work just fine and you will have a screen that shows your archive id.:
If you run into permissions or authorization errors - please follow these steps on setting up authorization for the AWS SDK. I recommend using a Credentials File (2nd option from top). Other problems could be wrong Vault Name or it cant find the file on your machine.
When you go back to the Glacier console, you will not see any files uploaded. Glacier is low cost and slow moving compared to s3 and so your Vault contents are updated once a day.
As long as you get an ID in step 6, your file was successfully stored in Glacier.
Hope this helps and you find success.
Make sure your region is consistent. In the following code, "eu-west-1" is used in the Connect call, but "us-west-1" is used for authAws.Region.
bool success = rest.Connect("glacier.eu-west-1.amazonaws.com", port, bTls, bAutoReconnect);
Chilkat.AuthAws authAws = new Chilkat.AuthAws();
authAws.AccessKey = ;
authAws.SecretKey = ;
authAws.ServiceName = "glacier";
authAws.Region = "us-west-1";
I am working on an app for an Okuma lathe.
I would like to be able to put the lathe into an alarm state from the app. I am not getting any errors and the app runs on the machine, but it doesn't go into an NC alarm state.
The line before it does change the text of alarmLabel.
I am using alarmLabel for troubleshooting.
Can anyone provide an example of SetUserAlarm in C#?
Does anyone see what is wrong with my code?
alarmLabel.Text = "Alarm ON";
objCMDMachine.SetUserAlarm(
Okuma.CLCMDAPI.Enumerations.UserAlarmEnum.C,
"Test Alarm",
Okuma.CLCMDAPI.Enumerations.UserAlarmSubSystemEnum.All
);
Your example code there looks okay to me.
To successfully generate a machine alarm, the API must have the licensed feature UserAlarm.
(Okuma.Lathe.UserAlarm in the okuma.api.lic license file).
You can confirm that a machine has this option by using the SCOUT library:
UserAlarmLathe = Okuma.Scout.LicenseChecker.License_UserAlarm_L;
if (UserAlarmLathe.Status == Enums.LicenseStatus.Valid)
{
// ...
}
Additionally, the machine on which the API resides must also have the THiNC ALARM option.
If your machine does not have the option, it can be ordered by contacting your Okuma Distributor and asking for option code " :911-0010 - THiNC ALARM "
The presence of this option can be confirmed by checking the Lathe Spec Code NC-B No. 4, Bit 3. You can check this spec code in your application using either THINC API or SCOUT.
Using THINC API:
Okuma.CLDATAPI.DataAPI.CSpec SpecCodeClass = new Okuma.CLDATAPI.DataAPI.CSpec();
bool THiNK_ALARM = SpecCodeClass.GetBSpecCode(4, 3);
if (THiNK_ALARM)
{
// ...
}
Using SCOUT:
if (Okuma.Scout.SpecCode.NCB.MachineSpecCodeFileExists)
{
if (Okuma.Scout.SpecCode.NCB.SpecFileIsValid)
{
bool THiNK_ALARM = Okuma.Scout.SpecCode.NCB.Bit(
Okuma.Scout.Enums.NCBSpecGroup.NCB1MG, 4, 3);
if (THiNK_ALARM)
{
// ...
}
}
}
So I have been recently trying to add Google Play Game Services to a project my buddy and I are working on.
I figured I would start with the sign in, as that is necessary for anything else that we wanted to add like achievements and leaderboards.
Anyway, I have published a closed Alpha to the google play store with my buddies dev and my own dev emails as the testers. I have set up my OAuth2 Client ID, SHA 1, AndroidManifest file, and other Game Services we are hoping for.
I then in Unity included the most recent Google Play Games Plugin (0.9.50), and set up the Resources and Client ID into our project. I of course have my Key and such for a Signed APK for our Closed Alpha test.
I then set up a button for Sign In within our scene, and have my code set up as follows:
void Start ()
{
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder()
.RequestEmail()
.RequestServerAuthCode(false)
.RequestIdToken()
.Build();
//DEBUGGING ONLY
PlayGamesPlatform.DebugLogEnabled = true;
PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.Activate();
// Does nothing either . . . .
Social.Instance.Authenticate((bool success) => { SignInCallback(success); }, false);
}
public void SignIn()
{
_signInNotification.text = "WARMER";
if (!PlayGamesPlatform.Instance.localUser.authenticated)
{
_signInNotification.text = "SIGNING IN";
Social.localUser.Authenticate((bool success) => { SignInCallback(success); });
}
else
{
PlayGamesPlatform.Instance.SignOut();
_signInNotification.text = "OUT";
}
}
private void SignInCallback(bool success)
{
if (success)
{
Debug.Log("(Something) Signed in!");
_signInNotification.text = "Signed In as : " + Social.localUser.userName;
}
else
{
Debug.Log("(Something) Sign-In Failed!");
_signInNotification.text = "Sign-In Failed!";
}
}[/code]
I have some text that lets me know what part of the code was accessed or run. The sign in button calls the SignIn() function, but only the text 'WARMER' is shown. The Social.localUser.Authenticate() function never seems to be called.
I have tried multiple solutions, changes, variations, etc. However when I click the SignIn button, absolutely nothing happens. No error, no warnings, no text saying Sign-In Failed, nothing.
Not quite sure what I am missing, any ideas would be greatly appreciated! :)
One problem I've realized with debugging Google Play Services problems is that the errors that pop up are from a separate activity, since the sign-in prompt is outside the app. You are probably getting an error response, but it's not from your program. Because of this, you might need to disable any filters in your console to see all errors (if you have Android Studio, the logcat should show all responses from a plugged-in device when it's set to No Filters).
In my case, the plugin had an AndroidManifest file (GooglePlayGames/Plugins/Android/GooglePlayGamesManifest.plugin folder) where the APP_ID had a value with a space in front of it. I believe this was an old workaround to convert the value to a string, but now the app required that it was a numeric value, so deleting the space solved my problem.
Hope this helps!
To set up Google Play Game Services we followed the documentation here and it guided us through all the needed steps.
What we found when we couldn't log in is that while testing your application your OAuth 2.0 client ID (on Google API Console > Credentials) should use the SHA-1 Signing-certificate fingerprint key from your Upload certificate and when it's time to publish the SHA-1 key should be from the App signing certificate. Both certificates can be found on your Google Play Console > All applications (choose the correct one) > Release management > App signing.
Is there any API for writing a C# program that could interface with Windows update, and use it to selectively install certain updates?
I'm thinking somewhere along the lines of storing a list in a central repository of approved updates. Then the client side applications (which would have to be installed once) would interface with Windows Update to determine what updates are available, then install the ones that are on the approved list. That way the updates are still applied automatically from a client-side perspective, but I can select which updates are being applied.
This is not my role in the company by the way, I was really just wondering if there is an API for windows update and how to use it.
Add a Reference to WUApiLib to your C# project.
using WUApiLib;
protected override void OnLoad(EventArgs e){
base.OnLoad(e);
UpdateSession uSession = new UpdateSession();
IUpdateSearcher uSearcher = uSession.CreateUpdateSearcher();
uSearcher.Online = false;
try {
ISearchResult sResult = uSearcher.Search("IsInstalled=1 And IsHidden=0");
textBox1.Text = "Found " + sResult.Updates.Count + " updates" + Environment.NewLine;
foreach (IUpdate update in sResult.Updates) {
textBox1.AppendText(update.Title + Environment.NewLine);
}
}
catch (Exception ex) {
Console.WriteLine("Something went wrong: " + ex.Message);
}
}
Given you have a form with a TextBox this will give you a list of the currently installed updates. See http://msdn.microsoft.com/en-us/library/aa387102(VS.85).aspx for more documentation.
This will, however, not allow you to find KB hotfixes which are not distributed via Windows Update.
The easiest way to do what you want is using WSUS. It's free and basically lets you setup your own local windows update server where you decide which updates are "approved" for your computers. Neither the WSUS server nor the clients need to be in a domain, though it makes it easier to configure the clients if they are. If you have different sets of machines that need different sets of updates approved, that's also supported.
Not only does this accomplish your stated goal, it saves your overall network bandwidth as well by only downloading the updates once from the WSUS server.
If in your context you're allowed to use Windows Server Update Service (WSUS), it will give you access to the Microsoft.UpdateServices.Administration Namespace.
From there, you should be able to do some nice things :)
P-L right. I tried first the Christoph Grimmer-Die method, and in some case, it was not working. I guess it was due to different version of .net or OS architecture (32 or 64 bits).
Then, to be sure that my program get always the Windows Update waiting list of each of my computer domain, I did the following :
Install a serveur with WSUS (may save some internet bandwith) : http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=5216
Add all your workstations & servers to your WSUS server
Get SimpleImpersonation Lib to run this program with different admin right (optional)
Install only the administration console component on your dev workstation and run the following program :
It will print in the console all Windows updates with UpdateInstallationStates.Downloaded
using System;
using Microsoft.UpdateServices.Administration;
using SimpleImpersonation;
namespace MAJSRS_CalendarChecker
{
class WSUS
{
public WSUS()
{
// I use impersonation to use other logon than mine. Remove the following "using" if not needed
using (Impersonation.LogonUser("mydomain.local", "admin_account_wsus", "Password", LogonType.Batch))
{
ComputerTargetScope scope = new ComputerTargetScope();
IUpdateServer server = AdminProxy.GetUpdateServer("wsus_server.mydomain.local", false, 80);
ComputerTargetCollection targets = server.GetComputerTargets(scope);
// Search
targets = server.SearchComputerTargets("any_server_name_or_ip");
// To get only on server FindTarget method
IComputerTarget target = FindTarget(targets, "any_server_name_or_ip");
Console.WriteLine(target.FullDomainName);
IUpdateSummary summary = target.GetUpdateInstallationSummary();
UpdateScope _updateScope = new UpdateScope();
// See in UpdateInstallationStates all other properties criteria
_updateScope.IncludedInstallationStates = UpdateInstallationStates.Downloaded;
UpdateInstallationInfoCollection updatesInfo = target.GetUpdateInstallationInfoPerUpdate(_updateScope);
int updateCount = updatesInfo.Count;
foreach (IUpdateInstallationInfo updateInfo in updatesInfo)
{
Console.WriteLine(updateInfo.GetUpdate().Title);
}
}
}
public IComputerTarget FindTarget(ComputerTargetCollection coll, string computername)
{
foreach (IComputerTarget target in coll)
{
if (target.FullDomainName.Contains(computername.ToLower()))
return target;
}
return null;
}
}
}