Macro to find my documents folder

    Aug 31 2010 | 10:33 pm
    Does anyone know of a way to find the my documents folder for the current user windows operating systems? The user needs to be able to read and write a temp file to a directory. This needs directory needs to be available to all users or needs to be available to the current user like the "My documents" folder. Any ideas on how to find this folder dynamically?

    • Sep 07 2010 | 5:03 pm
      I wrote an external for Windows which you can use to ask for the environment variables. One of them should be the userprofile
      Here is a link to a snippet how to read out all environment variables in c
      #include "ext.h"							// standard Max include, always required
      #include "ext_obex.h"						// required for new style Max object
      #include  //Needed for getenv()
      #include  //Needed for strings
      ////////////////////////// object struct
      typedef struct _commonprogramfiles
      	t_object	ob;
      	t_atom		val;
      	t_symbol	*name;
      	void		*out;
      } t_commonprogramfiles;
      ///////////////////////// function prototypes
      //// standard set
      void *commonprogramfiles_new(t_symbol *s, long argc, t_atom *argv);
      void commonprogramfiles_free(t_commonprogramfiles *x);
      void commonprogramfiles_assist(t_commonprogramfiles *x, void *b, long m, long a, char *s);
      void commonprogramfiles_int(t_commonprogramfiles *x, long n);
      void commonprogramfiles_float(t_commonprogramfiles *x, double f);
      void commonprogramfiles_anything(t_commonprogramfiles *x, t_symbol *s, long ac, t_atom *av);
      void commonprogramfiles_bang(t_commonprogramfiles *x);
      void commonprogramfiles_identify(t_commonprogramfiles *x);
      void commonprogramfiles_dblclick(t_commonprogramfiles *x);
      void commonprogramfiles_acant(t_commonprogramfiles *x);
      void commonprogramfiles_getenv(t_commonprogramfiles *x, t_symbol *myEnv);
      //////////////////////// global class pointer variable
      void *commonprogramfiles_class;
      int main(void)
      	t_class *c;
      	c = class_new("commonprogramfiles", (method)commonprogramfiles_new, (method)commonprogramfiles_free, (long)sizeof(t_commonprogramfiles),
      				  0L /* leave NULL!! */, A_GIMME, 0);
          class_addmethod(c, (method)commonprogramfiles_bang,			"bang", 0);
          class_addmethod(c, (method)commonprogramfiles_int,			"int",		A_LONG, 0);
          class_addmethod(c, (method)commonprogramfiles_float,			"float",	A_FLOAT, 0);
          class_addmethod(c, (method)commonprogramfiles_anything,		"anything",	A_GIMME, 0);
          class_addmethod(c, (method)commonprogramfiles_identify,		"identify", 0);
      	CLASS_METHOD_ATTR_PARSE(c, "identify", "undocumented", gensym("long"), 0, "1");
      	// we want to 'reveal' the otherwise hidden 'xyzzy' method
          class_addmethod(c, (method)commonprogramfiles_anything,		"xyzzy", A_GIMME, 0);
      	// here's an otherwise undocumented method, which does something that the user can't actually
      	// do from the patcher however, we want them to know about it for some weird documentation reason.
      	// so let's make it documentable. it won't appear in the quickref, because we can't send it from a message.
      	class_addmethod(c, (method)commonprogramfiles_acant,			"blooop", A_CANT, 0);
      	CLASS_METHOD_ATTR_PARSE(c, "blooop", "documentable", gensym("long"), 0, "1");
      	/* you CAN'T call this from the patcher */
          class_addmethod(c, (method)commonprogramfiles_assist,			"assist",		A_CANT, 0);
          class_addmethod(c, (method)commonprogramfiles_dblclick,			"dblclick",		A_CANT, 0);
          class_addmethod(c, (method)commonprogramfiles_getenv,			"getenv", A_SYM, 0);
      	CLASS_ATTR_SYM(c, "name", 0, t_commonprogramfiles, name);
      	class_register(CLASS_BOX, c);
      	commonprogramfiles_class = c;
      	return 0;
      void commonprogramfiles_acant(t_commonprogramfiles *x)
      	object_post((t_object *)x, "can't touch this!");
      void commonprogramfiles_assist(t_commonprogramfiles *x, void *b, long m, long a, char *s)
      	if (m == ASSIST_INLET) { //inlet
      		sprintf(s, "I am inlet %ld", a);
      	else {	// outlet
      		sprintf(s, "I am outlet %ld", a);
      void commonprogramfiles_free(t_commonprogramfiles *x)
      void commonprogramfiles_dblclick(t_commonprogramfiles *x)
      	object_post((t_object *)x, "I got a double-click");
      void commonprogramfiles_int(t_commonprogramfiles *x, long n)
      	atom_setlong(&x->val, n);
      void commonprogramfiles_float(t_commonprogramfiles *x, double f)
      	atom_setfloat(&x->val, f);
      void commonprogramfiles_anything(t_commonprogramfiles *x, t_symbol *s, long ac, t_atom *av)
      	if (s == gensym("xyzzy")) {
      		object_post((t_object *)x, "A hollow voice says 'Plugh'");
      	} else {
      		atom_setsym(&x->val, s);
      void commonprogramfiles_bang(t_commonprogramfiles *x)
      	switch (x->val.a_type) {
      		case A_LONG: outlet_int(x->out, atom_getlong(&x->val)); break;
      		case A_FLOAT: outlet_float(x->out, atom_getfloat(&x->val)); break;
      		case A_SYM: outlet_anything(x->out, atom_getsym(&x->val), 0, NULL); break;
      		default: break;
      void commonprogramfiles_identify(t_commonprogramfiles *x)
      	object_post((t_object *)x, "my name is %s", x->name->s_name);
      void *commonprogramfiles_new(t_symbol *s, long argc, t_atom *argv)
      	t_commonprogramfiles *x = NULL;
      	if (x = (t_commonprogramfiles *)object_alloc(commonprogramfiles_class)) {
      		x->name = gensym("");
      		if (argc && argv) {
      			x->name = atom_getsym(argv);
      		if (!x->name || x->name == gensym(""))
      			x->name = symbol_unique();
      		atom_setlong(&x->val, 0);
      		x->out = outlet_new(x, NULL);
      	return (x);
      void commonprogramfiles_getenv(t_commonprogramfiles *x, t_symbol *myEnv)
      	t_symbol bla;
      	char toConform[1024];
      	bla.s_name = getenv(myEnv->s_name);
      	path_nameconform(bla.s_name, toConform, PATH_STYLE_SLASH, PATH_TYPE_ABSOLUTE);
      	outlet_anything(x->out, gensym(toConform), 0, NULL);
    • Sep 07 2010 | 5:04 pm
      Hi again,
      missed the mostimportant thing. After you created the external you can use it sending a message "getenv " to it.
      Best, Johannes