I'm trying to use LestMove to be more precise
the second implementation method where it says:
Option 2:
Copy the following files into your project:
PFMoveApplication.h
PFMoveApplication.m
If your project has ARC enabled, you'll want to disable ARC on the above files. You can do so by adding -fno-objc-arc compiler flag to your PFMoveApplication.m source file. See How can I disable ARC for a single file in a project?
If your application is localized, also copy the 'MoveApplication.string' files into your project.
Link your application against Security.framework.
In your app delegate's "-[applicationWillFinishLaunching:]" method, call the PFMoveToApplicationsFolderIfNecessary function at the very top.
but I'm not able to call the method / Class, could someone help me with this issue? Thanks in advance!
In general, there are a couple of ways to set up an Objective-C class in your AppleScriptObjC project:
Add the file(s) to the project - the Objective-C class name will be
the one used in the #interface/#implementation declarations
Add an outlet property in the AppleScript class/script you are using, e.g. property someProperty : missing value
Instantiate the class programmatically:
set someProperty to current application's ClassName's alloc's init()
or
Connect stuff up with the Interface Builder:
Add an NSObject (blue cube) from the library to your project
Set the class of the object/cube to the class name of the Objective-C file(s) in the Identity Inspector
Connect the AppDelegate IB Outlet to the object/cube in the Connections Inspector
After setting up the outlet property, the Objective-C methods can be used like any other script/class:
someProperty's handler()
That LetsMove project wasn't really set up for AppleScriptObjC, but I was able to tweak it a bit to get it running. I'm not that great at writing Objective-C, but the following worked for me using a new default AppleScript project with Xcode 10 in Mojave (the original file is over 500 lines long, so I'm just highlighting the changes):
Add PFMoveApplication.h and PFMoveApplication.m files to the project (the class name is LetsMove)
Add Security.framework to Link Binary With Libraries in Build Phases
As described in the original project README, add the compiler flag -fno-objc-arc to the Objective-C file in Compile Sources of the Build Phases
-- Now to alter the Objective-C files a bit:
Move the #interface declaration to the .h file and include the redefined method signatures below in it:
The PFMoveToApplicationsFolderIfNecessary and PFMoveIsInProgress methods are redefined as instance methods:
- (void)PFMoveToApplicationsFolderIfNecessary;
- (BOOL)PFMoveIsInProgress;
Redefine the above method signatures in the .m file, and include those methods in the #implementation section - to do this, move the #end to just before the helper methods (after the PFMoveIsInProgress method)
Remove the isMainThread statement at the beginning of the PFMoveToApplicationsFolderIfNecessary method - this is not not needed (AppleScript normally runs on the main thread), and fixes another issue
There is still a little stuff in there from the original app such as NSUserDefaults, so for your own project, give it a look to see if anything else needs changing (dialog text, etc)
And finally, in the AppDelegate.applescipt file, the following was added to applicationWillFinishLaunching:
current application's LetsMove's alloc's init()'s PFMoveToApplicationsFolderIfNecessary()
I have a C++ CLR/CLI project, I wonder how to embed a localized satellite dll into my exe application, I found similar solutions but it's for C# projects which is pretty different from my project structure.
Is it possible to embed it directly into the binary?
By the way I'm getting issues with namespaces, it seems my custom namespace is not linked to my localized resource file.
I've been searching for hours to find a solution for a C++ CLR/CLI project which is pretty different comparing with C# projects which apparently comes with Build Action and Custom Tool Namespace all these options we don't have in a CLR/CLI project, it's really important, especially if we have changed Namespaces so we gotta use Resource Logical Name instead. Here's my answer how to solve Namespace issues, this also works for localized resource files linked to satellite dlls.
After your localized satellite dll is generated, include that in your project as Compiled Managed Resource you can set that by opening its file property and setting the Item Type. In projects such as C# you won't find that but something similar like "Embedded Resource". Anyways this is intended to C++ CLR/CLI projects only. If you have changed namespaces, don't forget to set Resource Logical Name of the respective resource file.
Next step is to do some code in order to embed that dll into our exe application, here's a good one for that:
Since C++ CLR/CLI doesn't support lambda expressions we have to do this way:
private: System::Reflection::Assembly^ currentDomainAssemblyResolve(System::Object^ sender, System::ResolveEventArgs^ args) {
System::Reflection::AssemblyName^ assemblyName = gcnew System::Reflection::AssemblyName(args->Name);
System::String^ resourceName = assemblyName->Name + ".dll";
System::IO::Stream^ stream = System::Reflection::Assembly::GetExecutingAssembly()->GetManifestResourceStream(resourceName);
array<Byte>^ assemblyData = gcnew array<Byte>((unsigned long) stream->Length);
try {
stream->Read(assemblyData, 0, assemblyData->Length);
} finally {
if (stream != nullptr) delete stream;
}
return System::Reflection::Assembly::Load(assemblyData);
}
Usage:
//Put it in your constructor before InitializeComponent()
MyClass(void) {
AppDomain::CurrentDomain->AssemblyResolve += gcnew System::ResolveEventHandler(this, &MyNameSpace::MyClass::currentDomainAssemblyResolve);
InitializeComponent();
}
So now it's no longer necessary satellite dlls to load your localized resources.
Use a free application packer to bundle files into a single exe.
https://enigmaprotector.com/en/aboutvb.html
This one is free, I use it and it works very well for me.
I've scoured the web and stackoverflow for this answer but can't find anything. I have written a com object in C++ (for the fist time) that works when used in vbscript and through cocreateinstance in an executable file. So I decided to see if it would work in Excel VBA.
So I went into "References" and located my object there. Checked the box and started coding away. The following is the VBA code.
Function doCos(x As Double) As Double
Dim t As SimpleLib.IMath
Set t = New SimpleLib.IMath ' <- "Invalid use of New keyword" error here
doCos = t.Cos(x)
End Function
Intellisense recognizes my object in the Dim statement, but it does not appear when I use a Set statement. Obviously I am using a registered type library or else intellisense wouldn't work at all. Again, the com object can be used in vbscript or an executable, but for some reason can't be used, at least with the new keyword, in VBA.
Does anyone have an idea what may be wrong, or what may have to be added to the com object? Thanks.
One approach is to define a coclass in the IDL that includes the interface needed (IMath in my case). NOTE: That the [default] interface is hidden by default. So I simply defined interface IUnknown as the default. After compiling with MIDL a type library is generated which one should register with regtlibv12.exe.
I then included an additional IF statement in DllGetClassObject like if (rclsid == CLSID_Math) where CLSID_Math is corresponds to the CLSID defined in the file automatically generated from MIDL. All I did was copy and paste the body of the IF statement from if ( rclsid == IID_IMath ), updated the DLLRegisterServer and DLLUnRegisterServer functions, recompiled the project, and regsvr32.exe.
So the following works now.
Function docos(x As Double) As Double
Dim a As SimpleLib.IMath
Set a = New SimpleLib.Math
docos = a.Cos(x)
End Function
Thanks to Hans for the tip about the coclass. Learned something new and useful.
I have written a DLL function in C++, which I am calling from VBA (Excel).
How can I setup the Visual Studio properties to allow me to debug the function? I have tried specifying Excel, but that doesn’t seem to work.
You have two choices: "direct debug", or "attach".
I strongly prefer the "direct debug" approach for a long list of reasons omitted from here.
There are steps required on both the DLL and Excel/VBA sides, your posting is unclear if all of those steps are addressed.
There are variations on the following:
1) In VS, depending on the version, enter Project Settings, or Project Properties, or equivalent, in the "Debug (not release) Target", go to the Debug or Debugging settings. :
a) There will be an field called "Executable for debugging session", or "command", or something like that depending on VS ver. Here, enter the full path of your Excel exe
b) Optionally, if the same "test spread sheet" is used frequently, enter the full path of your xls (or whatever) in the field called "Command argument", or "program argument" or as in your VS ver.
You may need to surround this with double quotes (e.g. if there are spaces in your path/file names).
c) You can also set the output of your project to a Dir that is "addin helpful", such as a Dir called AddIn (c.f. having the DLL end up in Debug (or Release) Dirs)
... it is assumed that your DLL has all the bits required to export the functions, with the project being of type DLL, plus any DLLEXPORT and compiler directives, etc etc.
... the specifics of the DLLEXPORT settings (and related compiler switches) and Calling Convention will determine many things ... it is assumed you have done all that correctly and consistently (and especially consistently with what the Excel-side is expecting).
... your DLL may or may not have a DLL_Main, if it does, more discussion is required.
2) Before anything else, be sure to have created the Excel-side "interface" for your DLL, ie. the "Add-In". This can be either via .xla, or via .xll. I strongly suggest the .xla route as your first approach.
See the Excel help files etc for creating the .xla
Then, in your XLA's VBA Module(s), declare the functions/subs etc from your DLL. For example, if you have a DLL called Add2_DLL.dll, which contains an exported function "add2_pho_xl", then:
Public Declare Function Add2_Pho_XX Lib "E:\EclipseWorkSpace\Add2_DLL\Debug\Add2_DLL.dll" _
Alias "add2_pho_xl" (A As Double, B As Double) As Double
I have used the Alias approach here, for reasons required below.
In many instances, this declaration can be used directly as User Defined Function (UDF) in your sheets, etc. However, for a vast number of cases, you will need to create a VBA "spinner" function/sub that creates the "ultimate" UDF, and relies on this direct entry function (see below). This is also a very long story, but necessary where more complex matters are required (arrays, variants, etc etc).
NOTICE:
a) the DLL's full path is required unless special steps have been taken. If your Addin is for general distribution ... a much longer discussion is required.
b) the Alias must be the EXACT entry name of the function in your DLL. If you view near the end of the DLL (or .Def) files, and unless you set your DLL modules as Private, those will show the entry names expected on the DLL side.
In this example, the entry name is NOT "decorated" due to the choices in the Calling Convention and compiler switches, but it could look something like
"_add2_pho_xl_#08" etc depending your choices.
... in any case, you must use whatever the DLL has.
3) Once both the .xla and dll exist (it is best if they are in the same Dir), Excel must be "told" about the Add-In. The easiest approach is Excel/Tools/Addins, but there are various strategies for "registering" DLL functions.
4) CRUCIALLY, the argument list properties/declarations MUST BE CONGRUENT with BOTH those in your DLL and the Calling Convention. Three (of many possible) examples of "issues" are,
(i) A Boolean on the VBA-side is two-bytes, if the Bool/Logical on your DLL side is 1-byte, then the Debug will fail, since the two sides "cannot connect" properly.
(ii) Strings ... this can be a very long story. It depends if sent ByVal or ByRef, it depends if the DLL side has "hidden length" Args, etc. etc. Remember, VBA uses COM/OLE VBStrings, which have their own can of worms.
(iii) Variants/Objects: these require a tome onto themselves
5) If ALL (and likely more) of the above have gone well, then in VS set your break points, if required, and "Go" or "Start" the debug (depending on VS ver, etc.). This should launch Excel, and if you also set the target xls, it will launch too. Go to the cell(s) where you addin function (e.g. =add2_pho_XX(A1, B1) ) resides, and execute the cell (sometimes using the "fx" menu item is useful, but there are other ways also).
Some hints:
a) if the func execution crashes/hangs etc Excel and does not even arrive back to the VS side, then likely there is a Arg list conflict (e.g. you are passing a Double to an Int or a million other possibilities), or Calling Convention conflict, etc.
b) In general, you may (while in the VS debug session) simultaneously perform a VBA debug session. That is, after starting the VS bebug, entre the VBA IDE, and set break points in VBA UDF's, if a "spinner" UDF's have been created. For example, a VBA UDF that relies also on the DLL's function.
Private Function Add2_Pho( FirstNum as Double, SecondNum as Double, Optional lMakeRed as Variant) As Variant
'
'
Add2_Pho = Add2_Pho_XX( FirstNum, SecondNum ) ' this is the actual DLL func accessed via Delcare above
'
If( IsMissing(lMakeRed) ) Then
Else
If( cBool(lMakeRed) ) Then
If( Add2_Pho < 0 ) Then
'
' ' make the result Red, or something
'
End If
End If
End If
'
'
End Function
... here, setting a break point at the first line can be helpful to see if the UDF is even entered on the VBA side. If it is, click Continue in VBA, and see if it makes it to the VS side, if not, check Args, Calling Convention, etc again, etc etc
c) If the cell's content are #Value or some other unexpected result, then at least the UDF is "recognised" but not functioning correctly, either due to sheet->VBA issues, or VBA-> DLL issues, or after the return DLL-> VBA
d) Save often! and Use the VBA IDE's Debug/ Compile VBA Project before running anything just make sure VBA internal consistency.
e) Also, if you are using VBA/XLA's, then get a copy of CleanProject (VBA can mess up its internals sometimes, and this Tool will be a life saver)
Please make sure that Debug mode is the active mode.
How to debug your DLL with Excel/VBA
I can compile the solution with no errors, but when I'll try to run it, I get a crash window:
An unhandled exception of type
'System.Resources.MissingManifestResourceException' occurred in mscorlib.dll
Additional information: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "<myformname>.resources" was corerctly embedded or linked into assembly "<myprojectname>" at compile time, or that all the satellite assemblies required are loaded and fully signed.
And after I press Break it throws me to the line:
this->Icon = (cli::safe_cast<System::Drawing::Icon^ >(resources->GetObject(L"$this.Icon")));
If I comment this line out, everything works just fine, but my program doesn't have icon.
Anyone else had this problem? Found a solution? I couldn't find anything clear enough for me to understand, problem is really annoying me, only solution I found was to declare my form class before any other classes, but I don't even have any other classes in my solution?
I also have only one project in this solution, ms support said something about having multiple projects, which I don't have, so it was no use either.
Take a look here :
http://www.mztools.com/articles/2005/MZ2005007.aspx
The exception is thrown because your icon cannot be located. You will probably need to compiles your resources under one .dll and put this under en-US subfolder on your project output. It did the trick for me at least. There are probably other solutions to your problem too.
Do not panic like I did. The root cause of the problem is that the compiled resource file is different from the one that is asked to load at runtime. This happens because the underlying build-script cannot detect the filename or namespace changes made after the form is created.
For example, At first we started a project named x . And our $(RootNamespace) becomes x. And we created a form named y. So our XML resource file y.resx gets compiled into x.y.resource . At this point the icon change works.
Now somehow we changed the project name or the namespace to z. But our $(RootNamespace) remains the x. While at compile-time it wrongly generates old x.y.resource, but at links-time it links z.y.resource. And at this point the icon change does not work.
It can also happen if the form is under some nested namespace which is not known in the project file.
It can be fixed by changing the compilation output of the y.resx file . It can be done by right-clicking the resource and changing the Resource Logical Name to $(RootNamespace).%(Filename).resources .
I will also make sure that ProjectName,AssemblyName and RootNamespace are the same in the .vcxproj file. Somehow if the form is declared under a nested namespace like RootNamespace.gui , then the output file of the resource should be $(RootNamespace).gui.%(Filename).resources .